|
57 | 57 | } |
58 | 58 | const matches = []; |
59 | 59 | for (const word of pattern) { |
| 60 | + if (!word || word.length === 0) continue; |
60 | 61 | let startIndex = 0; |
61 | 62 | while ((startIndex = lowerText.indexOf(word, startIndex)) !== -1) { |
62 | 63 | matches.push({ |
|
118 | 119 | } |
119 | 120 | return matches; |
120 | 121 | } |
121 | | - class SearchCache { |
122 | | - constructor(options2 = {}) { |
123 | | - this.cache = /* @__PURE__ */ new Map(); |
124 | | - this.hitCount = 0; |
125 | | - this.missCount = 0; |
126 | | - this.options = { |
127 | | - maxSize: options2.maxSize || 1e3, |
128 | | - ttl: options2.ttl || 6e4 |
129 | | - }; |
130 | | - } |
131 | | - get(key) { |
132 | | - const entry = this.cache.get(key); |
133 | | - if (!entry) { |
134 | | - this.missCount++; |
135 | | - return void 0; |
136 | | - } |
137 | | - if (Date.now() - entry.timestamp > this.options.ttl) { |
138 | | - this.cache.delete(key); |
139 | | - this.missCount++; |
140 | | - return void 0; |
141 | | - } |
142 | | - entry.hits++; |
143 | | - this.hitCount++; |
144 | | - return entry.value; |
145 | | - } |
146 | | - set(key, value) { |
147 | | - if (this.cache.size >= this.options.maxSize) { |
148 | | - this.evictOldest(); |
149 | | - } |
150 | | - this.cache.set(key, { |
151 | | - value, |
152 | | - timestamp: Date.now(), |
153 | | - hits: 0 |
154 | | - }); |
155 | | - } |
156 | | - clear() { |
157 | | - this.cache.clear(); |
158 | | - this.hitCount = 0; |
159 | | - this.missCount = 0; |
160 | | - } |
161 | | - evictOldest() { |
162 | | - let oldestKey; |
163 | | - let lowestScore = Infinity; |
164 | | - for (const [key, entry] of this.cache) { |
165 | | - const score = entry.timestamp + entry.hits * 1e4; |
166 | | - if (score < lowestScore) { |
167 | | - lowestScore = score; |
168 | | - oldestKey = key; |
169 | | - } |
170 | | - } |
171 | | - if (oldestKey) { |
172 | | - this.cache.delete(oldestKey); |
173 | | - } |
174 | | - } |
175 | | - getStats() { |
176 | | - const total = this.hitCount + this.missCount; |
177 | | - const hitRate = total > 0 ? this.hitCount / total : 0; |
178 | | - return { |
179 | | - size: this.cache.size, |
180 | | - maxSize: this.options.maxSize, |
181 | | - ttl: this.options.ttl, |
182 | | - hits: this.hitCount, |
183 | | - misses: this.missCount, |
184 | | - hitRate: Math.round(hitRate * 1e4) / 100 |
185 | | - }; |
186 | | - } |
187 | | - has(key) { |
188 | | - const entry = this.cache.get(key); |
189 | | - if (!entry) return false; |
190 | | - if (Date.now() - entry.timestamp > this.options.ttl) { |
191 | | - this.cache.delete(key); |
192 | | - return false; |
193 | | - } |
194 | | - return true; |
195 | | - } |
196 | | - } |
197 | 122 | class SearchStrategy { |
198 | 123 | constructor(findMatchesFunction) { |
199 | 124 | this.findMatchesFunction = findMatchesFunction; |
200 | | - this.cache = new SearchCache({ maxSize: 500, ttl: 6e4 }); |
201 | 125 | } |
202 | 126 | matches(text, criteria) { |
203 | 127 | if (text === null || text.trim() === "" || !criteria) { |
204 | 128 | return false; |
205 | 129 | } |
206 | | - const cacheKey = this.getCacheKey(text, criteria); |
207 | | - const cached = this.cache.get(cacheKey); |
208 | | - if (cached !== void 0) { |
209 | | - return cached.matches; |
210 | | - } |
211 | | - const matchInfo = this.findMatchesInternal(text, criteria); |
212 | | - const result = { |
213 | | - matches: matchInfo.length > 0, |
214 | | - matchInfo |
215 | | - }; |
216 | | - this.cache.set(cacheKey, result); |
217 | | - return result.matches; |
| 130 | + const matchInfo = this.findMatchesFunction(text, criteria); |
| 131 | + return matchInfo.length > 0; |
218 | 132 | } |
219 | 133 | findMatches(text, criteria) { |
220 | 134 | if (text === null || text.trim() === "" || !criteria) { |
221 | 135 | return []; |
222 | 136 | } |
223 | | - const cacheKey = this.getCacheKey(text, criteria); |
224 | | - const cached = this.cache.get(cacheKey); |
225 | | - if (cached !== void 0) { |
226 | | - return cached.matchInfo; |
227 | | - } |
228 | | - const matchInfo = this.findMatchesInternal(text, criteria); |
229 | | - const result = { |
230 | | - matches: matchInfo.length > 0, |
231 | | - matchInfo |
232 | | - }; |
233 | | - this.cache.set(cacheKey, result); |
234 | | - return result.matchInfo; |
235 | | - } |
236 | | - findMatchesInternal(text, criteria) { |
237 | 137 | return this.findMatchesFunction(text, criteria); |
238 | 138 | } |
239 | | - getCacheKey(text, criteria) { |
240 | | - return `${text.length}:${criteria}:${text.substring(0, 20)}`; |
241 | | - } |
242 | | - clearCache() { |
243 | | - this.cache.clear(); |
244 | | - } |
245 | | - getCacheStats() { |
246 | | - const stats = this.cache.getStats(); |
247 | | - return { |
248 | | - hitRate: stats.hitRate, |
249 | | - size: stats.size |
250 | | - }; |
251 | | - } |
252 | 139 | } |
253 | 140 | const LiteralSearchStrategy = new SearchStrategy( |
254 | 141 | findLiteralMatches |
|
369 | 256 | sortMiddleware: NoSort, |
370 | 257 | noResultsText: "No results found", |
371 | 258 | limit: 10, |
372 | | - fuzzy: false, |
373 | 259 | strategy: "literal", |
374 | 260 | debounceTime: null, |
375 | 261 | exclude: [], |
376 | 262 | onSearch: () => { |
377 | | - } |
| 263 | + }, |
| 264 | + fuzzy: false |
| 265 | + // Deprecated, use strategy: 'fuzzy' instead |
378 | 266 | }; |
379 | 267 | const REQUIRED_OPTIONS = ["searchInput", "resultsContainer", "json"]; |
380 | 268 | const WHITELISTED_KEYS = /* @__PURE__ */ new Set([ |
|
412 | 300 | return clone(this.findMatches(this.data, criteria).sort(this.options.sortMiddleware)); |
413 | 301 | } |
414 | 302 | setOptions(newOptions) { |
| 303 | + let strategy = (newOptions == null ? void 0 : newOptions.strategy) || DEFAULT_OPTIONS.strategy; |
| 304 | + if ((newOptions == null ? void 0 : newOptions.fuzzy) && !(newOptions == null ? void 0 : newOptions.strategy)) { |
| 305 | + console.warn('[Simple Jekyll Search] Warning: fuzzy option is deprecated. Use strategy: "fuzzy" instead.'); |
| 306 | + strategy = "fuzzy"; |
| 307 | + } |
415 | 308 | this.options = { |
416 | | - fuzzy: (newOptions == null ? void 0 : newOptions.fuzzy) || DEFAULT_OPTIONS.fuzzy, |
417 | 309 | limit: (newOptions == null ? void 0 : newOptions.limit) || DEFAULT_OPTIONS.limit, |
418 | | - searchStrategy: this.searchStrategy((newOptions == null ? void 0 : newOptions.strategy) || newOptions.fuzzy && "fuzzy" || DEFAULT_OPTIONS.strategy), |
| 310 | + searchStrategy: this.searchStrategy(strategy), |
419 | 311 | sortMiddleware: (newOptions == null ? void 0 : newOptions.sortMiddleware) || DEFAULT_OPTIONS.sortMiddleware, |
420 | 312 | exclude: (newOptions == null ? void 0 : newOptions.exclude) || DEFAULT_OPTIONS.exclude, |
421 | | - strategy: (newOptions == null ? void 0 : newOptions.strategy) || DEFAULT_OPTIONS.strategy |
| 313 | + strategy |
422 | 314 | }; |
423 | 315 | } |
424 | 316 | addObject(obj) { |
|
608 | 500 | middleware: this.options.templateMiddleware |
609 | 501 | }); |
610 | 502 | this.repository.setOptions({ |
611 | | - fuzzy: this.options.fuzzy, |
612 | 503 | limit: this.options.limit, |
613 | 504 | sortMiddleware: this.options.sortMiddleware, |
614 | 505 | strategy: this.options.strategy, |
|
0 commit comments