@vielzeug/scout 26.10.14 → 26.10.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/scout.js CHANGED
@@ -1,2 +1,412 @@
1
- import{tapper as e}from"@vielzeug/arsenal";function toSearchMatcher(e,t){let n,r=-1,i=new Set;return(a,o)=>((o!==n||e.revision!==r)&&(n=o,r=e.revision,i=new Set(e.search(o,t).map(e=>e.item))),i.has(a))}function toFilterPredicate(e,t,n){let r=new Set(e.search(t,n).map(e=>e.item));return e=>r.has(e)}var t={Exact:0,FuzzyOnly:5,LabelContains:2,LabelStart:1,MetaContains:3,TextContains:4};function rankEntries(e,n,r={}){let i=n.trim().toLowerCase();if(!i)return[...e];let a=r.fuzzyIds??new Set,o=[];for(let n of e){let e=n.label.toLowerCase(),r=e===i?t.Exact:e.startsWith(i)?t.LabelStart:e.includes(i)?t.LabelContains:n.meta.toLowerCase().includes(i)?t.MetaContains:n.text.toLowerCase().includes(i)?t.TextContains:a.has(n.id)?t.FuzzyOnly:null;r!==null&&o.push([r,n])}return o.sort((e,t)=>e[0]-t[0]||e[1].label.localeCompare(t[1].label)||e[1].text.localeCompare(t[1].text)).map(([,e])=>e)}function dedupeEntries(e){let t=new Set;return e.filter(e=>{let n=`${e.label}\u0000${e.text}`.toLowerCase();return!t.has(n)&&(t.add(n),!0)})}function splitPattern(e,t){if(!t)return[{text:e}];let n=[],r=0;for(let i of e.matchAll(t)){if(i[0].length===0)continue;let t=i.index??0;t>r&&n.push({text:e.slice(r,t)}),n.push({matched:!0,text:i[0]}),r=t+i[0].length}return r<e.length&&n.push({text:e.slice(r)}),n.length?n:[{text:e}]}var n=/[.*+?^${}()|[\]\\]/g,escapeRegExp=e=>e.replace(n,`\\$&`),ScoutError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},ScoutDisposedError=class extends ScoutError{},ScoutConfigError=class extends ScoutError{};function tokenize(e){return e.toLowerCase().replace(/[^\p{L}\p{N}\s']/gu,` `).trim().replace(/\s+/g,` `)}function defaultStringify(e){return e==null?``:typeof e==`string`?e:typeof e==`number`||typeof e==`boolean`?String(e):Array.isArray(e)?e.filter(e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`).join(` `):``}function findMatchRanges(e,t){let n=e.toLowerCase(),r=tokenize(t).split(` `).filter(Boolean),i=[];for(let e of r){let t=0;for(;t<n.length;){let r=n.indexOf(e,t);if(r===-1)break;i.push([r,r+e.length]),t=r+1}}i.sort((e,t)=>e[0]-t[0]);let a=[];for(let e of i){let t=a[a.length-1];t&&e[0]<=t[1]?t[1]=Math.max(t[1],e[1]):a.push([e[0],e[1]])}return a}function highlight(e,t){if(!e)return[];if(!t.length)return[{highlighted:!1,text:e}];let n=[],r=0;for(let[i,a]of t)i>r&&n.push({highlighted:!1,text:e.slice(r,i)}),a>i&&n.push({highlighted:!0,text:e.slice(i,a)}),r=a;return r<e.length&&n.push({highlighted:!1,text:e.slice(r)}),n}function highlightField(e,t,n){return highlight(n,e.matches.find(e=>e.field===t)?.ranges??[])}function generateTrigrams(e){let t=new Set,n=` ${e} `;for(let e=0;e<n.length-2;e++)t.add(n.slice(e,e+3));return t}function overlapSimilarity(e,t){if(e.size===0||t.size===0)return 0;let n=0;for(let r of e)t.has(r)&&n++;return n<2&&n<e.size?0:n/Math.min(e.size,t.size)}function requireFiniteInteger(e,t,n){if(!Number.isFinite(e)||!Number.isInteger(e)||e<n)throw new ScoutConfigError(`${t} must be a finite integer greater than or equal to ${n}.`);return e}function requireFiniteNumber(e,t,n,r=1/0){if(!Number.isFinite(e)||e<n||e>r)throw new ScoutConfigError(`${t} must be a finite number between ${n} and ${r}.`);return e}function resolveFields(e){return e.map(e=>typeof e==`string`?{field:e,stringify:defaultStringify,weight:1}:{field:e.field,stringify:e.stringify??defaultStringify,weight:requireFiniteNumber(e.weight??1,`weight for field "${e.field}"`,Number.MIN_VALUE)})}function createIndex(e,t){if(t.fields.length===0)throw new ScoutConfigError(`createIndex: at least one field is required.`);let n=resolveFields(t.fields),r=n.reduce((e,t)=>Math.max(e,t.weight),1),i=requireFiniteNumber(t.threshold??.2,`threshold`,0,1),a=requireFiniteInteger(t.limit??50,`limit`,0),o=requireFiniteInteger(t.minQueryLength??3,`minQueryLength`,1),s=new Map,c=new Map,l=new Set,u=0;function notifyMutation(){u++;for(let e of l)e()}let d=null,f=null;function getQueryTrigrams(e){return e===d&&f!==null?f:(d=e,f=generateTrigrams(e),f)}function addFieldToIndex(e,t){for(let n of t){let t=c.get(n);t||(t=new Set,c.set(n,t)),t.add(e)}}function removeFieldFromIndex(e,t){for(let n of t){let t=c.get(n);t&&(t.delete(e),t.size===0&&c.delete(n))}}function addItem(e){let t=new Map,r=new Map;for(let{field:i,stringify:a}of n){let n=e[i],o=a(n),s=tokenize(o),c=s.length>=1?generateTrigrams(s):new Set;t.set(i,c),r.set(i,o),addFieldToIndex(e,c)}s.set(e,{trigrams:t,values:r})}function containmentScan(e){let t=new Set;for(let[n,r]of s)for(let i of r.values.values())if(i.toLowerCase().includes(e)){t.add(n);break}return t}function trigramCandidates(e){let t=new Set;for(let n of e){let e=c.get(n);if(e)for(let n of e)t.add(n)}return t}function scoreCandidate(e,t,i){let a=0;for(let{field:o,weight:s}of n){let n;if(t===null)n=+!!(i.values.get(o)??``).toLowerCase().includes(e);else{let e=i.trigrams.get(o);if(!e||e.size===0)continue;n=overlapSimilarity(t,e)}let c=s/r*n;c>a&&(a=c)}return a}function computeMatches(e,t){let r=[];for(let{field:i}of n){let n=t.get(i);if(!n)continue;let a=findMatchRanges(n,e);a.length>0&&r.push({field:i,ranges:a})}return r}function reindexItem(e){let t=s.get(e);if(!t)return!1;let r=!1;for(let{field:i,stringify:a}of n){let n=a(e[i]);if(n===t.values.get(i))continue;r=!0;let o=t.trigrams.get(i);o&&removeFieldFromIndex(e,o);let s=tokenize(n),c=s.length>=1?generateTrigrams(s):new Set;t.trigrams.set(i,c),t.values.set(i,n),addFieldToIndex(e,c)}return r}function removeItem(e){let t=s.get(e);if(!t)return!1;for(let n of t.trigrams.values())removeFieldFromIndex(e,n);return s.delete(e),!0}for(let t of e)s.has(t)||addItem(t);return{add(e){s.has(e)||(addItem(e),notifyMutation())},get items(){return[...s.keys()]},onMutate(e){return l.add(e),()=>{l.delete(e)}},reindex(e){reindexItem(e)&&notifyMutation()},remove(e){removeItem(e)&&notifyMutation()},get revision(){return u},search(e,t){let n=requireFiniteNumber(t?.threshold??i,`threshold`,0,1),r=requireFiniteInteger(t?.limit??a,`limit`,0),c=requireFiniteInteger(t?.minQueryLength??o,`minQueryLength`,1);if(!e.trim())return[...s.keys()].slice(0,r).map(e=>({item:e,matches:[],score:1}));let l=tokenize(e);if(!l)return[];let u=l.length<c?null:getQueryTrigrams(l),d=u===null?containmentScan(l):trigramCandidates(u),f=[];for(let e of d){let t=s.get(e);if(!t)continue;let r=scoreCandidate(l,u,t);if(r>=n){let n=computeMatches(l,t.values);f.push({item:e,matches:n,score:r})}}return f.sort((e,t)=>t.score-e.score).slice(0,r)},setItems(e){let t=new Set(e),n=[...t],r=!1;for(let e of[...s.keys()])t.has(e)||(removeItem(e),r=!0);for(let e of n)s.has(e)?reindexItem(e)&&(r=!0):(addItem(e),r=!0);let i=[...s.keys()];if(i.length!==n.length||i.some((e,t)=>e!==n[t])){let e=new Map(n.map(e=>[e,s.get(e)]));s.clear();for(let[t,n]of e)s.set(t,n);r=!0}r&&notifyMutation()},get size(){return s.size}}}var r=200;function notify(e){for(let t of[...e])try{t()}catch(e){queueMicrotask(()=>{throw e})}}function subscribe(e,t,n,r,i){if(r||n?.signal?.aborted)return()=>{};e.add(t);let unsubscribe=()=>{e.delete(t),n?.signal?.removeEventListener(`abort`,unsubscribe)};return n?.signal?.addEventListener(`abort`,unsubscribe,{once:!0,signal:i}),unsubscribe}function createSearch(t,n={}){let{debounce:i=r,limit:a,minQueryLength:o,threshold:s}=n;if(!Number.isSafeInteger(i)||i<0)throw new ScoutConfigError(`debounce must be a finite non-negative integer.`);let search=e=>t.search(e,{limit:a,minQueryLength:o,threshold:s}),createSnapshot=(e,t,n)=>Object.freeze({isSearching:t,query:e,results:Object.freeze(n)}),c=new Set,l=e(),u=new AbortController,d=createSnapshot(``,!1,search(``)),f=``,p=!1,m,publish=e=>{d=e,notify(c),l.emit({snapshot:e,type:`state-change`})},commit=e=>{f=e,publish(createSnapshot(e,!1,search(e)))},h=t.onMutate(()=>{publish(createSnapshot(d.query,d.isSearching,search(f)))}),assertActive=e=>{if(p)throw new ScoutDisposedError(`SearchState.${e}() called after dispose()`)},dispose=()=>{p||(p=!0,m!==void 0&&clearTimeout(m),m=void 0,h(),c.clear(),l.clear(),u.abort())};return{clear(){assertActive(`clear`),(d.query!==``||d.isSearching)&&(m!==void 0&&clearTimeout(m),m=void 0,commit(``))},get disposalSignal(){return u.signal},dispose,get disposed(){return p},getSnapshot(){return d},setQuery(e){if(assertActive(`setQuery`),e!==d.query){if(m!==void 0&&clearTimeout(m),m=void 0,e===f){publish(createSnapshot(e,!1,d.results));return}if(i===0){commit(e);return}publish(createSnapshot(e,!0,d.results)),m=setTimeout(()=>{m=void 0,commit(e)},i)}},subscribe(e,t){return subscribe(c,e,t,p,u.signal)},tap(e,t){return p?()=>{}:l.tap(e,t)},[Symbol.dispose]:dispose}}function createReactiveSearch(e,t){let n=createIndex(e,t),r=createSearch(n,t);return{clear:r.clear,get disposalSignal(){return r.disposalSignal},dispose:r.dispose,get disposed(){return r.disposed},getSnapshot:r.getSnapshot,index:n,setQuery:r.setQuery,subscribe:r.subscribe,tap:r.tap,[Symbol.dispose]:r[Symbol.dispose]}}function segmentWords(e){let t=getSegmenter();return t?[...t.segment(e)].filter(e=>e.isWordLike).map(e=>e.segment).join(` `):e}var i;function getSegmenter(){return i===void 0&&(i=typeof Intl>`u`||typeof Intl.Segmenter!=`function`?null:new Intl.Segmenter(void 0,{granularity:`word`})),i}export{ScoutConfigError,ScoutDisposedError,ScoutError,createIndex,createReactiveSearch,createSearch,dedupeEntries,escapeRegExp,findMatchRanges,highlight,highlightField,rankEntries,segmentWords,splitPattern,toFilterPredicate,toSearchMatcher};
1
+ import { tapper as e } from "@vielzeug/arsenal";
2
+ //#region src/adapters.ts
3
+ function toSearchMatcher(e, t) {
4
+ let n, r = -1, i = /* @__PURE__ */ new Set();
5
+ return (a, o) => ((o !== n || e.revision !== r) && (n = o, r = e.revision, i = new Set(e.search(o, t).map((e) => e.item))), i.has(a));
6
+ }
7
+ function toFilterPredicate(e, t, n) {
8
+ let r = new Set(e.search(t, n).map((e) => e.item));
9
+ return (e) => r.has(e);
10
+ }
11
+ //#endregion
12
+ //#region src/entries.ts
13
+ var t = {
14
+ Exact: 0,
15
+ FuzzyOnly: 5,
16
+ LabelContains: 2,
17
+ LabelStart: 1,
18
+ MetaContains: 3,
19
+ TextContains: 4
20
+ };
21
+ function rankEntries(e, n, r = {}) {
22
+ let i = n.trim().toLowerCase();
23
+ if (!i) return [...e];
24
+ let a = r.fuzzyIds ?? /* @__PURE__ */ new Set(), o = [];
25
+ for (let n of e) {
26
+ let e = n.label.toLowerCase(), r = e === i ? t.Exact : e.startsWith(i) ? t.LabelStart : e.includes(i) ? t.LabelContains : n.meta.toLowerCase().includes(i) ? t.MetaContains : n.text.toLowerCase().includes(i) ? t.TextContains : a.has(n.id) ? t.FuzzyOnly : null;
27
+ r !== null && o.push([r, n]);
28
+ }
29
+ return o.sort((e, t) => e[0] - t[0] || e[1].label.localeCompare(t[1].label) || e[1].text.localeCompare(t[1].text)).map(([, e]) => e);
30
+ }
31
+ function dedupeEntries(e) {
32
+ let t = /* @__PURE__ */ new Set();
33
+ return e.filter((e) => {
34
+ let n = `${e.label}\u0000${e.text}`.toLowerCase();
35
+ return !t.has(n) && (t.add(n), !0);
36
+ });
37
+ }
38
+ function splitPattern(e, t) {
39
+ if (!t) return [{ text: e }];
40
+ let n = [], r = 0;
41
+ for (let i of e.matchAll(t)) {
42
+ if (i[0].length === 0) continue;
43
+ let t = i.index ?? 0;
44
+ t > r && n.push({ text: e.slice(r, t) }), n.push({
45
+ matched: !0,
46
+ text: i[0]
47
+ }), r = t + i[0].length;
48
+ }
49
+ return r < e.length && n.push({ text: e.slice(r) }), n.length ? n : [{ text: e }];
50
+ }
51
+ var n = /[.*+?^${}()|[\]\\]/g, escapeRegExp = (e) => e.replace(n, "\\$&"), ScoutError = class extends Error {
52
+ constructor(e, t) {
53
+ super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
54
+ }
55
+ }, ScoutDisposedError = class extends ScoutError {}, ScoutConfigError = class extends ScoutError {};
56
+ //#endregion
57
+ //#region src/tokenize.ts
58
+ function tokenize(e) {
59
+ return e.toLowerCase().replace(/[^\p{L}\p{N}\s']/gu, " ").trim().replace(/\s+/g, " ");
60
+ }
61
+ function defaultStringify(e) {
62
+ return e == null ? "" : typeof e == "string" ? e : typeof e == "number" || typeof e == "boolean" ? String(e) : Array.isArray(e) ? e.filter((e) => typeof e == "string" || typeof e == "number" || typeof e == "boolean").join(" ") : "";
63
+ }
64
+ //#endregion
65
+ //#region src/highlight.ts
66
+ function findMatchRanges(e, t) {
67
+ let n = e.toLowerCase(), r = tokenize(t).split(" ").filter(Boolean), i = [];
68
+ for (let e of r) {
69
+ let t = 0;
70
+ for (; t < n.length;) {
71
+ let r = n.indexOf(e, t);
72
+ if (r === -1) break;
73
+ i.push([r, r + e.length]), t = r + 1;
74
+ }
75
+ }
76
+ i.sort((e, t) => e[0] - t[0]);
77
+ let a = [];
78
+ for (let e of i) {
79
+ let t = a[a.length - 1];
80
+ t && e[0] <= t[1] ? t[1] = Math.max(t[1], e[1]) : a.push([e[0], e[1]]);
81
+ }
82
+ return a;
83
+ }
84
+ function highlight(e, t) {
85
+ if (!e) return [];
86
+ if (!t.length) return [{
87
+ highlighted: !1,
88
+ text: e
89
+ }];
90
+ let n = [], r = 0;
91
+ for (let [i, a] of t) i > r && n.push({
92
+ highlighted: !1,
93
+ text: e.slice(r, i)
94
+ }), a > i && n.push({
95
+ highlighted: !0,
96
+ text: e.slice(i, a)
97
+ }), r = a;
98
+ return r < e.length && n.push({
99
+ highlighted: !1,
100
+ text: e.slice(r)
101
+ }), n;
102
+ }
103
+ function highlightField(e, t, n) {
104
+ return highlight(n, e.matches.find((e) => e.field === t)?.ranges ?? []);
105
+ }
106
+ //#endregion
107
+ //#region src/trigram.ts
108
+ function generateTrigrams(e) {
109
+ let t = /* @__PURE__ */ new Set(), n = ` ${e} `;
110
+ for (let e = 0; e < n.length - 2; e++) t.add(n.slice(e, e + 3));
111
+ return t;
112
+ }
113
+ function overlapSimilarity(e, t) {
114
+ if (e.size === 0 || t.size === 0) return 0;
115
+ let n = 0;
116
+ for (let r of e) t.has(r) && n++;
117
+ return n < 2 && n < e.size ? 0 : n / Math.min(e.size, t.size);
118
+ }
119
+ //#endregion
120
+ //#region src/scout-index.ts
121
+ function requireFiniteInteger(e, t, n) {
122
+ if (!Number.isFinite(e) || !Number.isInteger(e) || e < n) throw new ScoutConfigError(`${t} must be a finite integer greater than or equal to ${n}.`);
123
+ return e;
124
+ }
125
+ function requireFiniteNumber(e, t, n, r = Infinity) {
126
+ if (!Number.isFinite(e) || e < n || e > r) throw new ScoutConfigError(`${t} must be a finite number between ${n} and ${r}.`);
127
+ return e;
128
+ }
129
+ function resolveFields(e) {
130
+ return e.map((e) => typeof e == "string" ? {
131
+ field: e,
132
+ stringify: defaultStringify,
133
+ weight: 1
134
+ } : {
135
+ field: e.field,
136
+ stringify: e.stringify ?? defaultStringify,
137
+ weight: requireFiniteNumber(e.weight ?? 1, `weight for field "${e.field}"`, Number.MIN_VALUE)
138
+ });
139
+ }
140
+ function createIndex(e, t) {
141
+ if (t.fields.length === 0) throw new ScoutConfigError("createIndex: at least one field is required.");
142
+ let n = resolveFields(t.fields), r = n.reduce((e, t) => Math.max(e, t.weight), 1), i = requireFiniteNumber(t.threshold ?? .2, "threshold", 0, 1), a = requireFiniteInteger(t.limit ?? 50, "limit", 0), o = requireFiniteInteger(t.minQueryLength ?? 3, "minQueryLength", 1), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Set(), u = 0;
143
+ function notifyMutation() {
144
+ u++;
145
+ for (let e of l) e();
146
+ }
147
+ let d = null, f = null;
148
+ function getQueryTrigrams(e) {
149
+ return e === d && f !== null || (d = e, f = generateTrigrams(e)), f;
150
+ }
151
+ function addFieldToIndex(e, t) {
152
+ for (let n of t) {
153
+ let t = c.get(n);
154
+ t || (t = /* @__PURE__ */ new Set(), c.set(n, t)), t.add(e);
155
+ }
156
+ }
157
+ function removeFieldFromIndex(e, t) {
158
+ for (let n of t) {
159
+ let t = c.get(n);
160
+ t && (t.delete(e), t.size === 0 && c.delete(n));
161
+ }
162
+ }
163
+ function addItem(e) {
164
+ let t = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
165
+ for (let { field: i, stringify: a } of n) {
166
+ let n = e[i], o = a(n), s = tokenize(o), c = s.length >= 1 ? generateTrigrams(s) : /* @__PURE__ */ new Set();
167
+ t.set(i, c), r.set(i, o), addFieldToIndex(e, c);
168
+ }
169
+ s.set(e, {
170
+ trigrams: t,
171
+ values: r
172
+ });
173
+ }
174
+ function containmentScan(e) {
175
+ let t = /* @__PURE__ */ new Set();
176
+ for (let [n, r] of s) for (let i of r.values.values()) if (i.toLowerCase().includes(e)) {
177
+ t.add(n);
178
+ break;
179
+ }
180
+ return t;
181
+ }
182
+ function trigramCandidates(e) {
183
+ let t = /* @__PURE__ */ new Set();
184
+ for (let n of e) {
185
+ let e = c.get(n);
186
+ if (e) for (let n of e) t.add(n);
187
+ }
188
+ return t;
189
+ }
190
+ function scoreCandidate(e, t, i) {
191
+ let a = 0;
192
+ for (let { field: o, weight: s } of n) {
193
+ let n;
194
+ if (t === null) n = +!!(i.values.get(o) ?? "").toLowerCase().includes(e);
195
+ else {
196
+ let e = i.trigrams.get(o);
197
+ if (!e || e.size === 0) continue;
198
+ n = overlapSimilarity(t, e);
199
+ }
200
+ let c = s / r * n;
201
+ c > a && (a = c);
202
+ }
203
+ return a;
204
+ }
205
+ function computeMatches(e, t) {
206
+ let r = [];
207
+ for (let { field: i } of n) {
208
+ let n = t.get(i);
209
+ if (!n) continue;
210
+ let a = findMatchRanges(n, e);
211
+ a.length > 0 && r.push({
212
+ field: i,
213
+ ranges: a
214
+ });
215
+ }
216
+ return r;
217
+ }
218
+ function reindexItem(e) {
219
+ let t = s.get(e);
220
+ if (!t) return !1;
221
+ let r = !1;
222
+ for (let { field: i, stringify: a } of n) {
223
+ let n = a(e[i]);
224
+ if (n === t.values.get(i)) continue;
225
+ r = !0;
226
+ let o = t.trigrams.get(i);
227
+ o && removeFieldFromIndex(e, o);
228
+ let s = tokenize(n), c = s.length >= 1 ? generateTrigrams(s) : /* @__PURE__ */ new Set();
229
+ t.trigrams.set(i, c), t.values.set(i, n), addFieldToIndex(e, c);
230
+ }
231
+ return r;
232
+ }
233
+ function removeItem(e) {
234
+ let t = s.get(e);
235
+ if (!t) return !1;
236
+ for (let n of t.trigrams.values()) removeFieldFromIndex(e, n);
237
+ return s.delete(e), !0;
238
+ }
239
+ for (let t of e) s.has(t) || addItem(t);
240
+ return {
241
+ add(e) {
242
+ s.has(e) || (addItem(e), notifyMutation());
243
+ },
244
+ get items() {
245
+ return [...s.keys()];
246
+ },
247
+ onMutate(e) {
248
+ return l.add(e), () => {
249
+ l.delete(e);
250
+ };
251
+ },
252
+ reindex(e) {
253
+ reindexItem(e) && notifyMutation();
254
+ },
255
+ remove(e) {
256
+ removeItem(e) && notifyMutation();
257
+ },
258
+ get revision() {
259
+ return u;
260
+ },
261
+ search(e, t) {
262
+ let n = requireFiniteNumber(t?.threshold ?? i, "threshold", 0, 1), r = requireFiniteInteger(t?.limit ?? a, "limit", 0), c = requireFiniteInteger(t?.minQueryLength ?? o, "minQueryLength", 1);
263
+ if (!e.trim()) return [...s.keys()].slice(0, r).map((e) => ({
264
+ item: e,
265
+ matches: [],
266
+ score: 1
267
+ }));
268
+ let l = tokenize(e);
269
+ if (!l) return [];
270
+ let u = l.length < c ? null : getQueryTrigrams(l), d = u === null ? containmentScan(l) : trigramCandidates(u), f = [];
271
+ for (let e of d) {
272
+ let t = s.get(e);
273
+ if (!t) continue;
274
+ let r = scoreCandidate(l, u, t);
275
+ if (r >= n) {
276
+ let n = computeMatches(l, t.values);
277
+ f.push({
278
+ item: e,
279
+ matches: n,
280
+ score: r
281
+ });
282
+ }
283
+ }
284
+ return f.sort((e, t) => t.score - e.score).slice(0, r);
285
+ },
286
+ setItems(e) {
287
+ let t = new Set(e), n = [...t], r = !1;
288
+ for (let e of [...s.keys()]) t.has(e) || (removeItem(e), r = !0);
289
+ for (let e of n) s.has(e) ? reindexItem(e) && (r = !0) : (addItem(e), r = !0);
290
+ let i = [...s.keys()];
291
+ if (i.length !== n.length || i.some((e, t) => e !== n[t])) {
292
+ let e = new Map(n.map((e) => [e, s.get(e)]));
293
+ s.clear();
294
+ for (let [t, n] of e) s.set(t, n);
295
+ r = !0;
296
+ }
297
+ r && notifyMutation();
298
+ },
299
+ get size() {
300
+ return s.size;
301
+ }
302
+ };
303
+ }
304
+ //#endregion
305
+ //#region src/reactive.ts
306
+ var r = 200;
307
+ function notify(e) {
308
+ for (let t of [...e]) try {
309
+ t();
310
+ } catch (e) {
311
+ queueMicrotask(() => {
312
+ throw e;
313
+ });
314
+ }
315
+ }
316
+ function subscribe(e, t, n, r, i) {
317
+ if (r || n?.signal?.aborted) return () => {};
318
+ e.add(t);
319
+ let unsubscribe = () => {
320
+ e.delete(t), n?.signal?.removeEventListener("abort", unsubscribe);
321
+ };
322
+ return n?.signal?.addEventListener("abort", unsubscribe, {
323
+ once: !0,
324
+ signal: i
325
+ }), unsubscribe;
326
+ }
327
+ function createSearch(t, n = {}) {
328
+ let { debounce: i = r, limit: a, minQueryLength: o, threshold: s } = n;
329
+ if (!Number.isSafeInteger(i) || i < 0) throw new ScoutConfigError("debounce must be a finite non-negative integer.");
330
+ let search = (e) => t.search(e, {
331
+ limit: a,
332
+ minQueryLength: o,
333
+ threshold: s
334
+ }), createSnapshot = (e, t, n) => Object.freeze({
335
+ isSearching: t,
336
+ query: e,
337
+ results: Object.freeze(n)
338
+ }), c = /* @__PURE__ */ new Set(), l = e(), u = new AbortController(), d = createSnapshot("", !1, search("")), f = "", p = !1, m, publish = (e) => {
339
+ d = e, notify(c), l.emit({
340
+ snapshot: e,
341
+ type: "state-change"
342
+ });
343
+ }, commit = (e) => {
344
+ f = e, publish(createSnapshot(e, !1, search(e)));
345
+ }, h = t.onMutate(() => {
346
+ publish(createSnapshot(d.query, d.isSearching, search(f)));
347
+ }), assertActive = (e) => {
348
+ if (p) throw new ScoutDisposedError(`SearchState.${e}() called after dispose()`);
349
+ }, dispose = () => {
350
+ p || (p = !0, m !== void 0 && clearTimeout(m), m = void 0, h(), c.clear(), l.clear(), u.abort());
351
+ };
352
+ return {
353
+ clear() {
354
+ assertActive("clear"), (d.query !== "" || d.isSearching) && (m !== void 0 && clearTimeout(m), m = void 0, commit(""));
355
+ },
356
+ get disposalSignal() {
357
+ return u.signal;
358
+ },
359
+ dispose,
360
+ get disposed() {
361
+ return p;
362
+ },
363
+ getSnapshot() {
364
+ return d;
365
+ },
366
+ setQuery(e) {
367
+ assertActive("setQuery"), e !== d.query && (m !== void 0 && clearTimeout(m), m = void 0, e === f ? publish(createSnapshot(e, !1, d.results)) : i === 0 ? commit(e) : (publish(createSnapshot(e, !0, d.results)), m = setTimeout(() => {
368
+ m = void 0, commit(e);
369
+ }, i)));
370
+ },
371
+ subscribe(e, t) {
372
+ return subscribe(c, e, t, p, u.signal);
373
+ },
374
+ tap(e, t) {
375
+ return p ? () => {} : l.tap(e, t);
376
+ },
377
+ [Symbol.dispose]: dispose
378
+ };
379
+ }
380
+ function createReactiveSearch(e, t) {
381
+ let n = createIndex(e, t), r = createSearch(n, t);
382
+ return {
383
+ clear: r.clear,
384
+ get disposalSignal() {
385
+ return r.disposalSignal;
386
+ },
387
+ dispose: r.dispose,
388
+ get disposed() {
389
+ return r.disposed;
390
+ },
391
+ getSnapshot: r.getSnapshot,
392
+ index: n,
393
+ setQuery: r.setQuery,
394
+ subscribe: r.subscribe,
395
+ tap: r.tap,
396
+ [Symbol.dispose]: r[Symbol.dispose]
397
+ };
398
+ }
399
+ //#endregion
400
+ //#region src/segment.ts
401
+ function segmentWords(e) {
402
+ let t = getSegmenter();
403
+ return t ? [...t.segment(e)].filter((e) => e.isWordLike).map((e) => e.segment).join(" ") : e;
404
+ }
405
+ var i;
406
+ function getSegmenter() {
407
+ return i === void 0 && (i = typeof Intl > "u" || typeof Intl.Segmenter != "function" ? null : new Intl.Segmenter(void 0, { granularity: "word" })), i;
408
+ }
409
+ //#endregion
410
+ export { ScoutConfigError, ScoutDisposedError, ScoutError, createIndex, createReactiveSearch, createSearch, dedupeEntries, escapeRegExp, findMatchRanges, highlight, highlightField, rankEntries, segmentWords, splitPattern, toFilterPredicate, toSearchMatcher };
411
+
2
412
  //# sourceMappingURL=scout.js.map