reg-cli 0.19.0-rc0 → 0.19.0-rc2

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.
@@ -4,12 +4,8 @@
4
4
  return !Array.isArray ? getTag(value) === "[object Array]" : Array.isArray(value);
5
5
  }
6
6
  function baseToString(value) {
7
- if (typeof value == "string") {
8
- return value;
9
- }
10
- if (typeof value === "bigint") {
11
- return value.toString();
12
- }
7
+ if (typeof value == "string") return value;
8
+ if (typeof value === "bigint") return value.toString();
13
9
  const result = value + "";
14
10
  return result == "0" && 1 / value == -Infinity ? "-0" : result;
15
11
  }
@@ -41,12 +37,14 @@
41
37
  return value == null ? value === void 0 ? "[object Undefined]" : "[object Null]" : Object.prototype.toString.call(value);
42
38
  }
43
39
  const INCORRECT_INDEX_TYPE = "Incorrect 'index' type";
40
+ const INVALID_DOC_INDEX = "Invalid doc index: must be a non-negative integer within the bounds of the docs array";
44
41
  const LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = (key) => `Invalid value for key ${key}`;
45
42
  const PATTERN_LENGTH_TOO_LARGE = (max) => `Pattern length exceeds max of ${max}.`;
46
43
  const MISSING_KEY_PROPERTY = (name) => `Missing ${name} property in key`;
47
44
  const INVALID_KEY_WEIGHT_VALUE = (key) => `Property 'weight' in key '${key}' must be a positive integer`;
45
+ const FUSE_MATCH_TOKEN_SEARCH_UNSUPPORTED = "Fuse.match does not support useTokenSearch: token search requires corpus-level statistics (df, fieldCount) that a one-off string comparison does not have. Use new Fuse(...).search(...) instead.";
48
46
  const hasOwn = Object.prototype.hasOwnProperty;
49
- class KeyStore {
47
+ var KeyStore = class {
50
48
  constructor(keys) {
51
49
  this._keys = [];
52
50
  this._keyMap = {};
@@ -70,7 +68,7 @@
70
68
  toJSON() {
71
69
  return JSON.stringify(this._keys);
72
70
  }
73
- }
71
+ };
74
72
  function createKey(key) {
75
73
  let path = null;
76
74
  let id = null;
@@ -82,20 +80,16 @@
82
80
  path = createKeyPath(key);
83
81
  id = createKeyId(key);
84
82
  } else {
85
- if (!hasOwn.call(key, "name")) {
86
- throw new Error(MISSING_KEY_PROPERTY("name"));
87
- }
83
+ if (!hasOwn.call(key, "name")) throw new Error(MISSING_KEY_PROPERTY("name"));
88
84
  const name = key.name;
89
85
  src = name;
90
- if (hasOwn.call(key, "weight")) {
86
+ if (hasOwn.call(key, "weight") && key.weight !== void 0) {
91
87
  weight = key.weight;
92
- if (weight <= 0) {
93
- throw new Error(INVALID_KEY_WEIGHT_VALUE(name));
94
- }
88
+ if (weight <= 0) throw new Error(INVALID_KEY_WEIGHT_VALUE(createKeyId(name)));
95
89
  }
96
90
  path = createKeyPath(name);
97
91
  id = createKeyId(name);
98
- getFn = key.getFn;
92
+ getFn = key.getFn ?? null;
99
93
  }
100
94
  return {
101
95
  path,
@@ -115,33 +109,22 @@
115
109
  const list = [];
116
110
  let arr = false;
117
111
  const deepGet = (obj2, path2, index, arrayIndex) => {
118
- if (!isDefined(obj2)) {
119
- return;
120
- }
121
- if (!path2[index]) {
122
- list.push(arrayIndex !== void 0 ? {
123
- v: obj2,
112
+ if (!isDefined(obj2)) return;
113
+ if (!path2[index]) list.push(arrayIndex !== void 0 ? {
114
+ v: obj2,
115
+ i: arrayIndex
116
+ } : obj2);
117
+ else {
118
+ const value = obj2[path2[index]];
119
+ if (!isDefined(value)) return;
120
+ if (index === path2.length - 1 && (isString(value) || isNumber(value) || isBoolean(value) || typeof value === "bigint")) list.push(arrayIndex !== void 0 ? {
121
+ v: toString(value),
124
122
  i: arrayIndex
125
- } : obj2);
126
- } else {
127
- const key = path2[index];
128
- const value = obj2[key];
129
- if (!isDefined(value)) {
130
- return;
131
- }
132
- if (index === path2.length - 1 && (isString(value) || isNumber(value) || isBoolean(value) || typeof value === "bigint")) {
133
- list.push(arrayIndex !== void 0 ? {
134
- v: toString(value),
135
- i: arrayIndex
136
- } : toString(value));
137
- } else if (isArray(value)) {
123
+ } : toString(value));
124
+ else if (isArray(value)) {
138
125
  arr = true;
139
- for (let i = 0, len = value.length; i < len; i += 1) {
140
- deepGet(value[i], path2, index + 1, i);
141
- }
142
- } else if (path2.length) {
143
- deepGet(value, path2, index + 1, arrayIndex);
144
- }
126
+ for (let i = 0, len = value.length; i < len; i += 1) deepGet(value[i], path2, index + 1, i);
127
+ } else if (path2.length) deepGet(value, path2, index + 1, arrayIndex);
145
128
  }
146
129
  };
147
130
  deepGet(obj, isString(path) ? path.split(".") : path, 0);
@@ -168,6 +151,8 @@
168
151
  const AdvancedOptions = {
169
152
  useExtendedSearch: false,
170
153
  useTokenSearch: false,
154
+ tokenize: void 0,
155
+ tokenMatch: "any",
171
156
  getFn: get,
172
157
  ignoreLocation: false,
173
158
  ignoreFieldNorm: false,
@@ -179,18 +164,25 @@
179
164
  ...FuzzyOptions,
180
165
  ...AdvancedOptions
181
166
  });
182
- const SPACE = /[^ ]+/g;
167
+ function isWordSeparator(code) {
168
+ return code >= 9 && code <= 13 || code === 32 || code === 160;
169
+ }
183
170
  function norm(weight = 1, mantissa = 3) {
184
171
  const cache = /* @__PURE__ */ new Map();
185
172
  const m = Math.pow(10, mantissa);
186
173
  return {
187
174
  get(value) {
188
- const numTokens = value.match(SPACE).length;
189
- if (cache.has(numTokens)) {
190
- return cache.get(numTokens);
191
- }
192
- const norm2 = 1 / Math.pow(numTokens, 0.5 * weight);
193
- const n = parseFloat(Math.round(norm2 * m) / m);
175
+ let numTokens = 0;
176
+ let inWord = false;
177
+ for (let i = 0; i < value.length; i++) if (!isWordSeparator(value.charCodeAt(i))) {
178
+ if (!inWord) {
179
+ numTokens++;
180
+ inWord = true;
181
+ }
182
+ } else inWord = false;
183
+ if (numTokens === 0) numTokens = 1;
184
+ if (cache.has(numTokens)) return cache.get(numTokens);
185
+ const n = Math.round(m / Math.pow(numTokens, 0.5 * weight)) / m;
194
186
  cache.set(numTokens, n);
195
187
  return n;
196
188
  },
@@ -199,11 +191,8 @@
199
191
  }
200
192
  };
201
193
  }
202
- class FuseIndex {
203
- constructor({
204
- getFn = Config.getFn,
205
- fieldNormWeight = Config.fieldNormWeight
206
- } = {}) {
194
+ var FuseIndex = class {
195
+ constructor({ getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
207
196
  this.norm = norm(fieldNormWeight, 3);
208
197
  this.getFn = getFn;
209
198
  this.isCreated = false;
@@ -226,44 +215,53 @@
226
215
  });
227
216
  }
228
217
  create() {
229
- if (this.isCreated || !this.docs.length) {
230
- return;
231
- }
218
+ if (this.isCreated || !this.docs.length) return;
232
219
  this.isCreated = true;
233
- if (isString(this.docs[0])) {
234
- this.docs.forEach((doc, docIndex) => {
235
- this._addString(doc, docIndex);
236
- });
237
- } else {
238
- this.docs.forEach((doc, docIndex) => {
239
- this._addObject(doc, docIndex);
240
- });
241
- }
220
+ const len = this.docs.length;
221
+ this.records = new Array(len);
222
+ let recordCount = 0;
223
+ if (isString(this.docs[0])) for (let i = 0; i < len; i++) {
224
+ const record = this._createStringRecord(this.docs[i], i);
225
+ if (record) this.records[recordCount++] = record;
226
+ }
227
+ else for (let i = 0; i < len; i++) this.records[recordCount++] = this._createObjectRecord(this.docs[i], i);
228
+ this.records.length = recordCount;
242
229
  this.norm.clear();
243
230
  }
244
- // Adds a doc to the end of the index
245
- add(doc) {
246
- const idx = this.size();
231
+ add(doc, docIndex) {
232
+ if (!Number.isInteger(docIndex) || docIndex < 0) throw new Error(INVALID_DOC_INDEX);
247
233
  if (isString(doc)) {
248
- this._addString(doc, idx);
249
- } else {
250
- this._addObject(doc, idx);
234
+ const record2 = this._createStringRecord(doc, docIndex);
235
+ if (record2) this.records.push(record2);
236
+ return record2;
251
237
  }
238
+ const record = this._createObjectRecord(doc, docIndex);
239
+ this.records.push(record);
240
+ return record;
252
241
  }
253
- // Removes the doc at the specified index of the index
254
242
  removeAt(idx) {
255
- this.records.splice(idx, 1);
256
- for (let i = idx, len = this.size(); i < len; i += 1) {
257
- this.records[i].i -= 1;
243
+ if (!Number.isInteger(idx) || idx < 0) throw new Error(INVALID_DOC_INDEX);
244
+ for (let i = 0, len = this.records.length; i < len; i += 1) if (this.records[i].i === idx) {
245
+ this.records.splice(i, 1);
246
+ break;
258
247
  }
248
+ for (let i = 0, len = this.records.length; i < len; i += 1) if (this.records[i].i > idx) this.records[i].i -= 1;
259
249
  }
260
- // Removes docs at the specified indices (must be sorted ascending)
261
250
  removeAll(indices) {
262
- for (let i = indices.length - 1; i >= 0; i -= 1) {
263
- this.records.splice(indices[i], 1);
264
- }
265
- for (let i = 0, len = this.records.length; i < len; i += 1) {
266
- this.records[i].i = i;
251
+ const toRemove = /* @__PURE__ */ new Set();
252
+ for (const v of indices) if (Number.isInteger(v) && v >= 0) toRemove.add(v);
253
+ if (toRemove.size === 0) return;
254
+ this.records = this.records.filter((r) => !toRemove.has(r.i));
255
+ const sorted = Array.from(toRemove).sort((a, b) => a - b);
256
+ for (const record of this.records) {
257
+ let lo = 0;
258
+ let hi = sorted.length;
259
+ while (lo < hi) {
260
+ const mid = lo + hi >>> 1;
261
+ if (sorted[mid] < record.i) lo = mid + 1;
262
+ else hi = mid;
263
+ }
264
+ record.i -= lo;
267
265
  }
268
266
  }
269
267
  getValueForItemAtKeyId(item, keyId) {
@@ -272,34 +270,28 @@
272
270
  size() {
273
271
  return this.records.length;
274
272
  }
275
- _addString(doc, docIndex) {
276
- if (!isDefined(doc) || isBlank(doc)) {
277
- return;
278
- }
279
- const record = {
273
+ _createStringRecord(doc, docIndex) {
274
+ if (!isDefined(doc) || isBlank(doc)) return null;
275
+ return {
280
276
  v: doc,
281
277
  i: docIndex,
282
278
  n: this.norm.get(doc)
283
279
  };
284
- this.records.push(record);
285
280
  }
286
- _addObject(doc, docIndex) {
281
+ _createObjectRecord(doc, docIndex) {
287
282
  const record = {
288
283
  i: docIndex,
289
284
  $: {}
290
285
  };
291
- this.keys.forEach((key, keyIndex) => {
286
+ for (let keyIndex = 0, keyLen = this.keys.length; keyIndex < keyLen; keyIndex++) {
287
+ const key = this.keys[keyIndex];
292
288
  const value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);
293
- if (!isDefined(value)) {
294
- return;
295
- }
289
+ if (!isDefined(value)) continue;
296
290
  if (isArray(value)) {
297
291
  const subRecords = [];
298
292
  for (let i = 0, len = value.length; i < len; i += 1) {
299
293
  const item = value[i];
300
- if (!isDefined(item)) {
301
- continue;
302
- }
294
+ if (!isDefined(item)) continue;
303
295
  if (isString(item)) {
304
296
  if (!isBlank(item)) {
305
297
  const subRecord = {
@@ -329,24 +321,17 @@
329
321
  };
330
322
  record.$[keyIndex] = subRecord;
331
323
  }
332
- });
333
- this.records.push(record);
324
+ }
325
+ return record;
334
326
  }
335
327
  toJSON() {
336
328
  return {
337
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
338
- keys: this.keys.map(({
339
- getFn,
340
- ...key
341
- }) => key),
329
+ keys: this.keys.map(({ getFn, ...key }) => key),
342
330
  records: this.records
343
331
  };
344
332
  }
345
- }
346
- function createIndex(keys, docs, {
347
- getFn = Config.getFn,
348
- fieldNormWeight = Config.fieldNormWeight
349
- } = {}) {
333
+ };
334
+ function createIndex(keys, docs, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
350
335
  const myIndex = new FuseIndex({
351
336
  getFn,
352
337
  fieldNormWeight
@@ -356,14 +341,8 @@
356
341
  myIndex.create();
357
342
  return myIndex;
358
343
  }
359
- function parseIndex(data, {
360
- getFn = Config.getFn,
361
- fieldNormWeight = Config.fieldNormWeight
362
- } = {}) {
363
- const {
364
- keys,
365
- records
366
- } = data;
344
+ function parseIndex(data, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
345
+ const { keys, records } = data;
367
346
  const myIndex = new FuseIndex({
368
347
  getFn,
369
348
  fieldNormWeight
@@ -379,34 +358,18 @@
379
358
  let i = 0;
380
359
  for (let len = matchmask.length; i < len; i += 1) {
381
360
  const match = matchmask[i];
382
- if (match && start === -1) {
383
- start = i;
384
- } else if (!match && start !== -1) {
361
+ if (match && start === -1) start = i;
362
+ else if (!match && start !== -1) {
385
363
  end = i - 1;
386
- if (end - start + 1 >= minMatchCharLength) {
387
- indices.push([start, end]);
388
- }
364
+ if (end - start + 1 >= minMatchCharLength) indices.push([start, end]);
389
365
  start = -1;
390
366
  }
391
367
  }
392
- if (matchmask[i - 1] && i - start >= minMatchCharLength) {
393
- indices.push([start, i - 1]);
394
- }
368
+ if (matchmask[i - 1] && i - start >= minMatchCharLength) indices.push([start, i - 1]);
395
369
  return indices;
396
370
  }
397
- const MAX_BITS = 32;
398
- function search(text, pattern, patternAlphabet, {
399
- location = Config.location,
400
- distance = Config.distance,
401
- threshold = Config.threshold,
402
- findAllMatches = Config.findAllMatches,
403
- minMatchCharLength = Config.minMatchCharLength,
404
- includeMatches = Config.includeMatches,
405
- ignoreLocation = Config.ignoreLocation
406
- } = {}) {
407
- if (pattern.length > MAX_BITS) {
408
- throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));
409
- }
371
+ function search(text, pattern, patternAlphabet, { location = Config.location, distance = Config.distance, threshold = Config.threshold, findAllMatches = Config.findAllMatches, minMatchCharLength = Config.minMatchCharLength, includeMatches = Config.includeMatches, ignoreLocation = Config.ignoreLocation } = {}) {
372
+ if (pattern.length > 32) throw new Error(PATTERN_LENGTH_TOO_LARGE(32));
410
373
  const patternLen = pattern.length;
411
374
  const textLen = text.length;
412
375
  const expectedLocation = Math.max(0, Math.min(location, textLen));
@@ -437,18 +400,15 @@
437
400
  bestLocation = -1;
438
401
  let lastBitArr = [];
439
402
  let finalScore = 1;
403
+ let bestErrors = 0;
440
404
  let binMax = patternLen + textLen;
441
405
  const mask = 1 << patternLen - 1;
442
406
  for (let i = 0; i < patternLen; i += 1) {
443
407
  let binMin = 0;
444
408
  let binMid = binMax;
445
409
  while (binMin < binMid) {
446
- const score2 = calcScore(i, expectedLocation + binMid);
447
- if (score2 <= currentThreshold) {
448
- binMin = binMid;
449
- } else {
450
- binMax = binMid;
451
- }
410
+ if (calcScore(i, expectedLocation + binMid) <= currentThreshold) binMin = binMid;
411
+ else binMax = binMid;
452
412
  binMid = Math.floor((binMax - binMin) / 2 + binMin);
453
413
  }
454
414
  binMax = binMid;
@@ -459,43 +419,34 @@
459
419
  for (let j = finish; j >= start; j -= 1) {
460
420
  const currentLocation = j - 1;
461
421
  const charMatch = patternAlphabet[text[currentLocation]];
462
- if (computeMatches) {
463
- matchMask[currentLocation] = +!!charMatch;
464
- }
465
422
  bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;
466
- if (i) {
467
- bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];
468
- }
423
+ if (i) bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];
469
424
  if (bitArr[j] & mask) {
470
425
  finalScore = calcScore(i, currentLocation);
471
426
  if (finalScore <= currentThreshold) {
472
427
  currentThreshold = finalScore;
473
428
  bestLocation = currentLocation;
474
- if (bestLocation <= expectedLocation) {
475
- break;
476
- }
429
+ bestErrors = i;
430
+ if (bestLocation <= expectedLocation) break;
477
431
  start = Math.max(1, 2 * expectedLocation - bestLocation);
478
432
  }
479
433
  }
480
434
  }
481
- const score = calcScore(i + 1, expectedLocation);
482
- if (score > currentThreshold) {
483
- break;
484
- }
435
+ if (calcScore(i + 1, expectedLocation) > currentThreshold) break;
485
436
  lastBitArr = bitArr;
486
437
  }
438
+ if (computeMatches && bestLocation >= 0) {
439
+ const matchEnd = Math.min(textLen - 1, bestLocation + patternLen - 1 + bestErrors);
440
+ for (let k = bestLocation; k <= matchEnd; k += 1) if (patternAlphabet[text[k]]) matchMask[k] = 1;
441
+ }
487
442
  const result = {
488
443
  isMatch: bestLocation >= 0,
489
- // Count exact matches (those with a score of 0) to be "almost" exact
490
444
  score: Math.max(1e-3, finalScore)
491
445
  };
492
446
  if (computeMatches) {
493
447
  const indices = convertMaskToIndices(matchMask, minMatchCharLength);
494
- if (!indices.length) {
495
- result.isMatch = false;
496
- } else if (includeMatches) {
497
- result.indices = indices;
498
- }
448
+ if (!indices.length) result.isMatch = false;
449
+ else if (includeMatches) result.indices = indices;
499
450
  }
500
451
  return result;
501
452
  }
@@ -514,54 +465,29 @@
514
465
  for (let i = 1, len = indices.length; i < len; i += 1) {
515
466
  const last = merged[merged.length - 1];
516
467
  const curr = indices[i];
517
- if (curr[0] <= last[1] + 1) {
518
- last[1] = Math.max(last[1], curr[1]);
519
- } else {
520
- merged.push(curr);
521
- }
468
+ if (curr[0] <= last[1] + 1) last[1] = Math.max(last[1], curr[1]);
469
+ else merged.push(curr);
522
470
  }
523
471
  return merged;
524
472
  }
525
473
  const NON_DECOMPOSABLE_MAP = {
526
474
  "ł": "l",
527
- // ł
528
475
  "Ł": "L",
529
- // Ł
530
476
  "đ": "d",
531
- // đ
532
477
  "Đ": "D",
533
- // Đ
534
478
  "ø": "o",
535
- // ø
536
479
  "Ø": "O",
537
- // Ø
538
480
  "ħ": "h",
539
- // ħ
540
481
  "Ħ": "H",
541
- // Ħ
542
482
  "ŧ": "t",
543
- // ŧ
544
483
  "Ŧ": "T",
545
- // Ŧ
546
484
  "ı": "i",
547
- // ı
548
485
  "ß": "ss"
549
- // ß
550
486
  };
551
487
  const NON_DECOMPOSABLE_RE = new RegExp("[" + Object.keys(NON_DECOMPOSABLE_MAP).join("") + "]", "g");
552
- const stripDiacritics = String.prototype.normalize ? (str) => str.normalize("NFD").replace(/[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]/g, "").replace(NON_DECOMPOSABLE_RE, (ch) => NON_DECOMPOSABLE_MAP[ch]) : (str) => str;
553
- class BitapSearch {
554
- constructor(pattern, {
555
- location = Config.location,
556
- threshold = Config.threshold,
557
- distance = Config.distance,
558
- includeMatches = Config.includeMatches,
559
- findAllMatches = Config.findAllMatches,
560
- minMatchCharLength = Config.minMatchCharLength,
561
- isCaseSensitive = Config.isCaseSensitive,
562
- ignoreDiacritics = Config.ignoreDiacritics,
563
- ignoreLocation = Config.ignoreLocation
564
- } = {}) {
488
+ const stripDiacritics = typeof String.prototype.normalize === "function" ? (str) => str.normalize("NFD").replace(/[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]/g, "").replace(NON_DECOMPOSABLE_RE, (ch) => NON_DECOMPOSABLE_MAP[ch]) : (str) => str;
489
+ var BitapSearch = class {
490
+ constructor(pattern, { location = Config.location, threshold = Config.threshold, distance = Config.distance, includeMatches = Config.includeMatches, findAllMatches = Config.findAllMatches, minMatchCharLength = Config.minMatchCharLength, isCaseSensitive = Config.isCaseSensitive, ignoreDiacritics = Config.ignoreDiacritics, ignoreLocation = Config.ignoreLocation } = {}) {
565
491
  this.options = {
566
492
  location,
567
493
  threshold,
@@ -577,9 +503,7 @@
577
503
  pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
578
504
  this.pattern = pattern;
579
505
  this.chunks = [];
580
- if (!this.pattern.length) {
581
- return;
582
- }
506
+ if (!this.pattern.length) return;
583
507
  const addChunk = (pattern2, startIndex) => {
584
508
  this.chunks.push({
585
509
  pattern: pattern2,
@@ -588,61 +512,42 @@
588
512
  });
589
513
  };
590
514
  const len = this.pattern.length;
591
- if (len > MAX_BITS) {
515
+ if (len > 32) {
592
516
  let i = 0;
593
- const remainder = len % MAX_BITS;
517
+ const remainder = len % 32;
594
518
  const end = len - remainder;
595
519
  while (i < end) {
596
- addChunk(this.pattern.substr(i, MAX_BITS), i);
597
- i += MAX_BITS;
520
+ addChunk(this.pattern.substr(i, 32), i);
521
+ i += 32;
598
522
  }
599
523
  if (remainder) {
600
- const startIndex = len - MAX_BITS;
524
+ const startIndex = len - 32;
601
525
  addChunk(this.pattern.substr(startIndex), startIndex);
602
526
  }
603
- } else {
604
- addChunk(this.pattern, 0);
605
- }
527
+ } else addChunk(this.pattern, 0);
606
528
  }
607
529
  searchIn(text) {
608
- const {
609
- isCaseSensitive,
610
- ignoreDiacritics,
611
- includeMatches
612
- } = this.options;
530
+ const { isCaseSensitive, ignoreDiacritics, includeMatches } = this.options;
613
531
  text = isCaseSensitive ? text : text.toLowerCase();
614
532
  text = ignoreDiacritics ? stripDiacritics(text) : text;
615
533
  if (this.pattern === text) {
534
+ if (text.length < this.options.minMatchCharLength) return {
535
+ isMatch: false,
536
+ score: 1
537
+ };
616
538
  const result2 = {
617
539
  isMatch: true,
618
540
  score: 0
619
541
  };
620
- if (includeMatches) {
621
- result2.indices = [[0, text.length - 1]];
622
- }
542
+ if (includeMatches) result2.indices = [[0, text.length - 1]];
623
543
  return result2;
624
544
  }
625
- const {
626
- location,
627
- distance,
628
- threshold,
629
- findAllMatches,
630
- minMatchCharLength,
631
- ignoreLocation
632
- } = this.options;
545
+ const { location, distance, threshold, findAllMatches, minMatchCharLength, ignoreLocation } = this.options;
633
546
  const allIndices = [];
634
547
  let totalScore = 0;
635
548
  let hasMatches = false;
636
- this.chunks.forEach(({
637
- pattern,
638
- alphabet,
639
- startIndex
640
- }) => {
641
- const {
642
- isMatch,
643
- score,
644
- indices
645
- } = search(text, pattern, alphabet, {
549
+ this.chunks.forEach(({ pattern, alphabet, startIndex }) => {
550
+ const { isMatch, score, indices } = search(text, pattern, alphabet, {
646
551
  location: location + startIndex,
647
552
  distance,
648
553
  threshold,
@@ -651,249 +556,169 @@
651
556
  includeMatches,
652
557
  ignoreLocation
653
558
  });
654
- if (isMatch) {
655
- hasMatches = true;
656
- }
559
+ if (isMatch) hasMatches = true;
657
560
  totalScore += score;
658
- if (isMatch && indices) {
659
- allIndices.push(...indices);
660
- }
561
+ if (isMatch && indices) allIndices.push(...indices);
661
562
  });
662
563
  const result = {
663
564
  isMatch: hasMatches,
664
565
  score: hasMatches ? totalScore / this.chunks.length : 1
665
566
  };
666
- if (hasMatches && includeMatches) {
667
- result.indices = mergeIndices(allIndices);
668
- }
567
+ if (hasMatches && includeMatches) result.indices = mergeIndices(allIndices);
669
568
  return result;
670
569
  }
570
+ };
571
+ const MULTI_MATCH_TYPES = /* @__PURE__ */ new Set(["fuzzy", "include"]);
572
+ function isInverse(type) {
573
+ return type.startsWith("inverse");
671
574
  }
672
- class BaseMatch {
673
- constructor(pattern) {
674
- this.pattern = pattern;
675
- }
676
- static isMultiMatch(pattern) {
677
- return getMatch(pattern, this.multiRegex);
678
- }
679
- static isSingleMatch(pattern) {
680
- return getMatch(pattern, this.singleRegex);
681
- }
682
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
683
- search(_text) {
684
- return {
685
- isMatch: false,
686
- score: 1
687
- };
688
- }
689
- }
690
- function getMatch(pattern, exp) {
691
- const matches = pattern.match(exp);
692
- return matches ? matches[1] : null;
693
- }
694
- class ExactMatch extends BaseMatch {
695
- constructor(pattern) {
696
- super(pattern);
697
- }
698
- static get type() {
699
- return "exact";
700
- }
701
- static get multiRegex() {
702
- return /^="(.*)"$/;
703
- }
704
- static get singleRegex() {
705
- return /^=(.*)$/;
706
- }
707
- search(text) {
708
- const isMatch = text === this.pattern;
709
- return {
710
- isMatch,
711
- score: isMatch ? 0 : 1,
712
- indices: [0, this.pattern.length - 1]
713
- };
714
- }
715
- }
716
- class InverseExactMatch extends BaseMatch {
717
- constructor(pattern) {
718
- super(pattern);
719
- }
720
- static get type() {
721
- return "inverse-exact";
722
- }
723
- static get multiRegex() {
724
- return /^!"(.*)"$/;
725
- }
726
- static get singleRegex() {
727
- return /^!(.*)$/;
728
- }
729
- search(text) {
730
- const index = text.indexOf(this.pattern);
731
- const isMatch = index === -1;
732
- return {
733
- isMatch,
734
- score: isMatch ? 0 : 1,
735
- indices: [0, text.length - 1]
736
- };
737
- }
738
- }
739
- class PrefixExactMatch extends BaseMatch {
740
- constructor(pattern) {
741
- super(pattern);
742
- }
743
- static get type() {
744
- return "prefix-exact";
745
- }
746
- static get multiRegex() {
747
- return /^\^"(.*)"$/;
748
- }
749
- static get singleRegex() {
750
- return /^\^(.*)$/;
751
- }
752
- search(text) {
753
- const isMatch = text.startsWith(this.pattern);
754
- return {
755
- isMatch,
756
- score: isMatch ? 0 : 1,
757
- indices: [0, this.pattern.length - 1]
758
- };
759
- }
760
- }
761
- class InversePrefixExactMatch extends BaseMatch {
762
- constructor(pattern) {
763
- super(pattern);
764
- }
765
- static get type() {
766
- return "inverse-prefix-exact";
767
- }
768
- static get multiRegex() {
769
- return /^!\^"(.*)"$/;
770
- }
771
- static get singleRegex() {
772
- return /^!\^(.*)$/;
773
- }
774
- search(text) {
775
- const isMatch = !text.startsWith(this.pattern);
776
- return {
777
- isMatch,
778
- score: isMatch ? 0 : 1,
779
- indices: [0, text.length - 1]
780
- };
781
- }
782
- }
783
- class SuffixExactMatch extends BaseMatch {
784
- constructor(pattern) {
785
- super(pattern);
786
- }
787
- static get type() {
788
- return "suffix-exact";
789
- }
790
- static get multiRegex() {
791
- return /^"(.*)"\$$/;
792
- }
793
- static get singleRegex() {
794
- return /^(.*)\$$/;
795
- }
796
- search(text) {
797
- const isMatch = text.endsWith(this.pattern);
798
- return {
799
- isMatch,
800
- score: isMatch ? 0 : 1,
801
- indices: [text.length - this.pattern.length, text.length - 1]
802
- };
803
- }
804
- }
805
- class InverseSuffixExactMatch extends BaseMatch {
806
- constructor(pattern) {
807
- super(pattern);
808
- }
809
- static get type() {
810
- return "inverse-suffix-exact";
811
- }
812
- static get multiRegex() {
813
- return /^!"(.*)"\$$/;
814
- }
815
- static get singleRegex() {
816
- return /^!(.*)\$$/;
817
- }
818
- search(text) {
819
- const isMatch = !text.endsWith(this.pattern);
820
- return {
821
- isMatch,
822
- score: isMatch ? 0 : 1,
823
- indices: [0, text.length - 1]
824
- };
825
- }
826
- }
827
- class FuzzyMatch extends BaseMatch {
828
- constructor(pattern, {
829
- location = Config.location,
830
- threshold = Config.threshold,
831
- distance = Config.distance,
832
- includeMatches = Config.includeMatches,
833
- findAllMatches = Config.findAllMatches,
834
- minMatchCharLength = Config.minMatchCharLength,
835
- isCaseSensitive = Config.isCaseSensitive,
836
- ignoreDiacritics = Config.ignoreDiacritics,
837
- ignoreLocation = Config.ignoreLocation
838
- } = {}) {
839
- super(pattern);
840
- this._bitapSearch = new BitapSearch(pattern, {
841
- location,
842
- threshold,
843
- distance,
844
- includeMatches,
845
- findAllMatches,
846
- minMatchCharLength,
847
- isCaseSensitive,
848
- ignoreDiacritics,
849
- ignoreLocation
850
- });
851
- }
852
- static get type() {
853
- return "fuzzy";
854
- }
855
- static get multiRegex() {
856
- return /^"(.*)"$/;
857
- }
858
- static get singleRegex() {
859
- return /^(.*)$/;
860
- }
861
- search(text) {
862
- return this._bitapSearch.searchIn(text);
863
- }
864
- }
865
- class IncludeMatch extends BaseMatch {
866
- constructor(pattern) {
867
- super(pattern);
868
- }
869
- static get type() {
870
- return "include";
871
- }
872
- static get multiRegex() {
873
- return /^'"(.*)"$/;
874
- }
875
- static get singleRegex() {
876
- return /^'(.*)$/;
877
- }
878
- search(text) {
879
- let location = 0;
880
- let index;
881
- const indices = [];
882
- const patternLen = this.pattern.length;
883
- while ((index = text.indexOf(this.pattern, location)) > -1) {
884
- location = index + patternLen;
885
- indices.push([index, location - 1]);
575
+ const matchers = [
576
+ {
577
+ type: "exact",
578
+ multiRegex: /^="(.*)"$/,
579
+ singleRegex: /^=(.*)$/,
580
+ create: (pattern) => ({
581
+ type: "exact",
582
+ search(text) {
583
+ const isMatch = text === pattern;
584
+ return {
585
+ isMatch,
586
+ score: isMatch ? 0 : 1,
587
+ indices: [0, pattern.length - 1]
588
+ };
589
+ }
590
+ })
591
+ },
592
+ {
593
+ type: "include",
594
+ multiRegex: /^'"(.*)"$/,
595
+ singleRegex: /^'(.*)$/,
596
+ create: (pattern) => ({
597
+ type: "include",
598
+ search(text) {
599
+ let location = 0;
600
+ let index;
601
+ const indices = [];
602
+ const patternLen = pattern.length;
603
+ while ((index = text.indexOf(pattern, location)) > -1) {
604
+ location = index + patternLen;
605
+ indices.push([index, location - 1]);
606
+ }
607
+ const isMatch = !!indices.length;
608
+ return {
609
+ isMatch,
610
+ score: isMatch ? 0 : 1,
611
+ indices
612
+ };
613
+ }
614
+ })
615
+ },
616
+ {
617
+ type: "prefix-exact",
618
+ multiRegex: /^\^"(.*)"$/,
619
+ singleRegex: /^\^(.*)$/,
620
+ create: (pattern) => ({
621
+ type: "prefix-exact",
622
+ search(text) {
623
+ const isMatch = text.startsWith(pattern);
624
+ return {
625
+ isMatch,
626
+ score: isMatch ? 0 : 1,
627
+ indices: [0, pattern.length - 1]
628
+ };
629
+ }
630
+ })
631
+ },
632
+ {
633
+ type: "inverse-prefix-exact",
634
+ multiRegex: /^!\^"(.*)"$/,
635
+ singleRegex: /^!\^(.*)$/,
636
+ create: (pattern) => ({
637
+ type: "inverse-prefix-exact",
638
+ search(text) {
639
+ const isMatch = !text.startsWith(pattern);
640
+ return {
641
+ isMatch,
642
+ score: isMatch ? 0 : 1,
643
+ indices: [0, text.length - 1]
644
+ };
645
+ }
646
+ })
647
+ },
648
+ {
649
+ type: "inverse-suffix-exact",
650
+ multiRegex: /^!"(.*)"\$$/,
651
+ singleRegex: /^!(.*)\$$/,
652
+ create: (pattern) => ({
653
+ type: "inverse-suffix-exact",
654
+ search(text) {
655
+ const isMatch = !text.endsWith(pattern);
656
+ return {
657
+ isMatch,
658
+ score: isMatch ? 0 : 1,
659
+ indices: [0, text.length - 1]
660
+ };
661
+ }
662
+ })
663
+ },
664
+ {
665
+ type: "suffix-exact",
666
+ multiRegex: /^"(.*)"\$$/,
667
+ singleRegex: /^(.*)\$$/,
668
+ create: (pattern) => ({
669
+ type: "suffix-exact",
670
+ search(text) {
671
+ const isMatch = text.endsWith(pattern);
672
+ return {
673
+ isMatch,
674
+ score: isMatch ? 0 : 1,
675
+ indices: [text.length - pattern.length, text.length - 1]
676
+ };
677
+ }
678
+ })
679
+ },
680
+ {
681
+ type: "inverse-exact",
682
+ multiRegex: /^!"(.*)"$/,
683
+ singleRegex: /^!(.*)$/,
684
+ create: (pattern) => ({
685
+ type: "inverse-exact",
686
+ search(text) {
687
+ const isMatch = text.indexOf(pattern) === -1;
688
+ return {
689
+ isMatch,
690
+ score: isMatch ? 0 : 1,
691
+ indices: [0, text.length - 1]
692
+ };
693
+ }
694
+ })
695
+ },
696
+ {
697
+ type: "fuzzy",
698
+ multiRegex: /^"(.*)"$/,
699
+ singleRegex: /^(.*)$/,
700
+ create: (pattern, options = {}) => {
701
+ const bitap = new BitapSearch(pattern, {
702
+ location: options.location ?? Config.location,
703
+ threshold: options.threshold ?? Config.threshold,
704
+ distance: options.distance ?? Config.distance,
705
+ includeMatches: options.includeMatches ?? Config.includeMatches,
706
+ findAllMatches: options.findAllMatches ?? Config.findAllMatches,
707
+ minMatchCharLength: options.minMatchCharLength ?? Config.minMatchCharLength,
708
+ isCaseSensitive: options.isCaseSensitive ?? Config.isCaseSensitive,
709
+ ignoreDiacritics: options.ignoreDiacritics ?? Config.ignoreDiacritics,
710
+ ignoreLocation: options.ignoreLocation ?? Config.ignoreLocation
711
+ });
712
+ return {
713
+ type: "fuzzy",
714
+ search(text) {
715
+ return bitap.searchIn(text);
716
+ }
717
+ };
886
718
  }
887
- const isMatch = !!indices.length;
888
- return {
889
- isMatch,
890
- score: isMatch ? 0 : 1,
891
- indices
892
- };
893
719
  }
894
- }
895
- const searchers = [ExactMatch, IncludeMatch, PrefixExactMatch, InversePrefixExactMatch, InverseSuffixExactMatch, SuffixExactMatch, InverseExactMatch, FuzzyMatch];
896
- const searchersLen = searchers.length;
720
+ ];
721
+ const matchersLen = matchers.length;
897
722
  const ESCAPED_PIPE = "\0";
898
723
  const OR_TOKEN = "|";
899
724
  function tokenize(pattern) {
@@ -931,33 +756,33 @@
931
756
  }
932
757
  return tokens;
933
758
  }
759
+ function getMatch(pattern, exp) {
760
+ const matches = pattern.match(exp);
761
+ return matches ? matches[1] : null;
762
+ }
934
763
  function parseQuery(pattern, options = {}) {
935
- const escaped = pattern.replace(/\\\|/g, ESCAPED_PIPE);
936
- return escaped.split(OR_TOKEN).map((item) => {
937
- const restored = item.replace(/\u0000/g, "|");
938
- const query = tokenize(restored.trim()).filter((item2) => item2 && !!item2.trim());
764
+ return pattern.replace(/\\\|/g, ESCAPED_PIPE).split(OR_TOKEN).map((item) => {
765
+ const query = tokenize(item.replace(/\u0000/g, "|").trim()).filter((item2) => item2 && !!item2.trim());
939
766
  const results = [];
940
767
  for (let i = 0, len = query.length; i < len; i += 1) {
941
768
  const queryItem = query[i];
942
769
  let found = false;
943
770
  let idx = -1;
944
- while (!found && ++idx < searchersLen) {
945
- const searcher = searchers[idx];
946
- const token = searcher.isMultiMatch(queryItem);
771
+ while (!found && ++idx < matchersLen) {
772
+ const def = matchers[idx];
773
+ const token = getMatch(queryItem, def.multiRegex);
947
774
  if (token) {
948
- results.push(new searcher(token, options));
775
+ results.push(def.create(token, options));
949
776
  found = true;
950
777
  }
951
778
  }
952
- if (found) {
953
- continue;
954
- }
779
+ if (found) continue;
955
780
  idx = -1;
956
- while (++idx < searchersLen) {
957
- const searcher = searchers[idx];
958
- const token = searcher.isSingleMatch(queryItem);
781
+ while (++idx < matchersLen) {
782
+ const def = matchers[idx];
783
+ const token = getMatch(queryItem, def.singleRegex);
959
784
  if (token) {
960
- results.push(new searcher(token, options));
785
+ results.push(def.create(token, options));
961
786
  break;
962
787
  }
963
788
  }
@@ -965,19 +790,8 @@
965
790
  return results;
966
791
  });
967
792
  }
968
- const MultiMatchSet = /* @__PURE__ */ new Set([FuzzyMatch.type, IncludeMatch.type]);
969
- class ExtendedSearch {
970
- constructor(pattern, {
971
- isCaseSensitive = Config.isCaseSensitive,
972
- ignoreDiacritics = Config.ignoreDiacritics,
973
- includeMatches = Config.includeMatches,
974
- minMatchCharLength = Config.minMatchCharLength,
975
- ignoreLocation = Config.ignoreLocation,
976
- findAllMatches = Config.findAllMatches,
977
- location = Config.location,
978
- threshold = Config.threshold,
979
- distance = Config.distance
980
- } = {}) {
793
+ var ExtendedSearch = class {
794
+ constructor(pattern, { isCaseSensitive = Config.isCaseSensitive, ignoreDiacritics = Config.ignoreDiacritics, includeMatches = Config.includeMatches, minMatchCharLength = Config.minMatchCharLength, ignoreLocation = Config.ignoreLocation, findAllMatches = Config.findAllMatches, location = Config.location, threshold = Config.threshold, distance = Config.distance } = {}) {
981
795
  this.query = null;
982
796
  this.options = {
983
797
  isCaseSensitive,
@@ -998,22 +812,13 @@
998
812
  static condition(_, options) {
999
813
  return options.useExtendedSearch;
1000
814
  }
1001
- // Note: searchIn operates on a single text value and sets hasInverse on the
1002
- // result when inverse patterns are involved. _searchObjectList uses this to
1003
- // switch from "ANY key" to "ALL keys" aggregation. See #712.
1004
815
  searchIn(text) {
1005
816
  const query = this.query;
1006
- if (!query) {
1007
- return {
1008
- isMatch: false,
1009
- score: 1
1010
- };
1011
- }
1012
- const {
1013
- includeMatches,
1014
- isCaseSensitive,
1015
- ignoreDiacritics
1016
- } = this.options;
817
+ if (!query) return {
818
+ isMatch: false,
819
+ score: 1
820
+ };
821
+ const { includeMatches, isCaseSensitive, ignoreDiacritics } = this.options;
1017
822
  text = isCaseSensitive ? text : text.toLowerCase();
1018
823
  text = ignoreDiacritics ? stripDiacritics(text) : text;
1019
824
  let numMatches = 0;
@@ -1021,31 +826,19 @@
1021
826
  let totalScore = 0;
1022
827
  let hasInverse = false;
1023
828
  for (let i = 0, qLen = query.length; i < qLen; i += 1) {
1024
- const searchers2 = query[i];
829
+ const searchers = query[i];
1025
830
  allIndices.length = 0;
1026
831
  numMatches = 0;
1027
832
  hasInverse = false;
1028
- for (let j = 0, pLen = searchers2.length; j < pLen; j += 1) {
1029
- const searcher = searchers2[j];
1030
- const {
1031
- isMatch,
1032
- indices,
1033
- score
1034
- } = searcher.search(text);
833
+ for (let j = 0, pLen = searchers.length; j < pLen; j += 1) {
834
+ const matcher = searchers[j];
835
+ const { isMatch, indices, score } = matcher.search(text);
1035
836
  if (isMatch) {
1036
837
  numMatches += 1;
1037
838
  totalScore += score;
1038
- const type = searcher.constructor.type;
1039
- if (type.startsWith("inverse")) {
1040
- hasInverse = true;
1041
- }
1042
- if (includeMatches) {
1043
- if (MultiMatchSet.has(type)) {
1044
- allIndices.push(...indices);
1045
- } else {
1046
- allIndices.push(indices);
1047
- }
1048
- }
839
+ if (isInverse(matcher.type)) hasInverse = true;
840
+ if (includeMatches) if (MULTI_MATCH_TYPES.has(matcher.type)) allIndices.push(...indices);
841
+ else allIndices.push(indices);
1049
842
  } else {
1050
843
  totalScore = 0;
1051
844
  numMatches = 0;
@@ -1059,12 +852,8 @@
1059
852
  isMatch: true,
1060
853
  score: totalScore / numMatches
1061
854
  };
1062
- if (hasInverse) {
1063
- result.hasInverse = true;
1064
- }
1065
- if (includeMatches) {
1066
- result.indices = mergeIndices(allIndices);
1067
- }
855
+ if (hasInverse) result.hasInverse = true;
856
+ if (includeMatches) result.indices = mergeIndices(allIndices);
1068
857
  return result;
1069
858
  }
1070
859
  }
@@ -1073,7 +862,7 @@
1073
862
  score: 1
1074
863
  };
1075
864
  }
1076
- }
865
+ };
1077
866
  const registeredSearchers = [];
1078
867
  function register(...args) {
1079
868
  registeredSearchers.push(...args);
@@ -1081,9 +870,7 @@
1081
870
  function createSearcher(pattern, options) {
1082
871
  for (let i = 0, len = registeredSearchers.length; i < len; i += 1) {
1083
872
  const searcherClass = registeredSearchers[i];
1084
- if (searcherClass.condition(pattern, options)) {
1085
- return new searcherClass(pattern, options);
1086
- }
873
+ if (searcherClass.condition(pattern, options)) return new searcherClass(pattern, options);
1087
874
  }
1088
875
  return new BitapSearch(pattern, options);
1089
876
  }
@@ -1098,43 +885,29 @@
1098
885
  const isExpression = (query) => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);
1099
886
  const isPath = (query) => !!query[KeyType.PATH];
1100
887
  const isLeaf = (query) => !isArray(query) && isObject(query) && !isExpression(query);
1101
- const convertToExplicit = (query) => ({
1102
- [LogicalOperator.AND]: Object.keys(query).map((key) => ({
1103
- [key]: query[key]
1104
- }))
1105
- });
1106
- function parse(query, options, {
1107
- auto = true
1108
- } = {}) {
888
+ const convertToExplicit = (query) => ({ [LogicalOperator.AND]: Object.keys(query).map((key) => ({ [key]: query[key] })) });
889
+ function parse(query, options, { auto = true } = {}) {
1109
890
  const next = (query2) => {
1110
891
  if (isString(query2)) {
1111
892
  const obj = {
1112
893
  keyId: null,
1113
894
  pattern: query2
1114
895
  };
1115
- if (auto) {
1116
- obj.searcher = createSearcher(query2, options);
1117
- }
896
+ if (auto) obj.searcher = createSearcher(query2, options);
1118
897
  return obj;
1119
898
  }
1120
899
  const keys = Object.keys(query2);
1121
900
  const isQueryPath = isPath(query2);
1122
- if (!isQueryPath && keys.length > 1 && !isExpression(query2)) {
1123
- return next(convertToExplicit(query2));
1124
- }
901
+ if (!isQueryPath && keys.length > 1 && !isExpression(query2)) return next(convertToExplicit(query2));
1125
902
  if (isLeaf(query2)) {
1126
903
  const key = isQueryPath ? query2[KeyType.PATH] : keys[0];
1127
904
  const pattern = isQueryPath ? query2[KeyType.PATTERN] : query2[key];
1128
- if (!isString(pattern)) {
1129
- throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
1130
- }
905
+ if (!isString(pattern)) throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
1131
906
  const obj = {
1132
907
  keyId: createKeyId(key),
1133
908
  pattern
1134
909
  };
1135
- if (auto) {
1136
- obj.searcher = createSearcher(pattern, options);
1137
- }
910
+ if (auto) obj.searcher = createSearcher(pattern, options);
1138
911
  return obj;
1139
912
  }
1140
913
  const node = {
@@ -1143,70 +916,54 @@
1143
916
  };
1144
917
  keys.forEach((key) => {
1145
918
  const value = query2[key];
1146
- if (isArray(value)) {
1147
- value.forEach((item) => {
1148
- node.children.push(next(item));
1149
- });
1150
- }
919
+ if (isArray(value)) value.forEach((item) => {
920
+ node.children.push(next(item));
921
+ });
1151
922
  });
1152
923
  return node;
1153
924
  };
1154
- if (!isExpression(query)) {
1155
- query = convertToExplicit(query);
1156
- }
925
+ if (!isExpression(query)) query = convertToExplicit(query);
1157
926
  return next(query);
1158
927
  }
1159
- function computeScoreSingle(matches, {
1160
- ignoreFieldNorm = Config.ignoreFieldNorm
1161
- }) {
928
+ function computeScoreSingle(matches, { ignoreFieldNorm = Config.ignoreFieldNorm }) {
1162
929
  let totalScore = 1;
1163
- matches.forEach(({
1164
- key,
1165
- norm: norm2,
1166
- score
1167
- }) => {
930
+ matches.forEach(({ key, norm: norm2, score }) => {
1168
931
  const weight = key ? key.weight : null;
1169
932
  totalScore *= Math.pow(score === 0 && weight ? Number.EPSILON : score, (weight || 1) * (ignoreFieldNorm ? 1 : norm2));
1170
933
  });
1171
934
  return totalScore;
1172
935
  }
1173
- function computeScore(results, {
1174
- ignoreFieldNorm = Config.ignoreFieldNorm
1175
- }) {
936
+ function computeScore(results, { ignoreFieldNorm = Config.ignoreFieldNorm }) {
1176
937
  results.forEach((result) => {
1177
- result.score = computeScoreSingle(result.matches, {
1178
- ignoreFieldNorm
1179
- });
938
+ result.score = computeScoreSingle(result.matches, { ignoreFieldNorm });
1180
939
  });
1181
940
  }
1182
- class MaxHeap {
1183
- constructor(limit) {
941
+ var MaxHeap = class {
942
+ constructor(limit, comparator) {
1184
943
  this.limit = limit;
1185
944
  this.heap = [];
945
+ this.comparator = comparator;
1186
946
  }
1187
947
  get size() {
1188
948
  return this.heap.length;
1189
949
  }
1190
- shouldInsert(score) {
1191
- return this.size < this.limit || score < this.heap[0].score;
1192
- }
1193
950
  insert(item) {
1194
951
  if (this.size < this.limit) {
1195
952
  this.heap.push(item);
1196
953
  this._bubbleUp(this.size - 1);
1197
- } else if (item.score < this.heap[0].score) {
954
+ } else if (this.comparator(item, this.heap[0]) < 0) {
1198
955
  this.heap[0] = item;
1199
956
  this._sinkDown(0);
1200
957
  }
1201
958
  }
1202
- extractSorted(sortFn) {
1203
- return this.heap.sort(sortFn);
959
+ extractSorted() {
960
+ return this.heap.sort(this.comparator);
1204
961
  }
1205
962
  _bubbleUp(i) {
1206
963
  const heap = this.heap;
1207
964
  while (i > 0) {
1208
965
  const parent = i - 1 >> 1;
1209
- if (heap[i].score <= heap[parent].score) break;
966
+ if (this.comparator(heap[i], heap[parent]) <= 0) break;
1210
967
  const tmp = heap[i];
1211
968
  heap[i] = heap[parent];
1212
969
  heap[parent] = tmp;
@@ -1221,12 +978,8 @@
1221
978
  i = largest;
1222
979
  const left = 2 * i + 1;
1223
980
  const right = 2 * i + 2;
1224
- if (left < len && heap[left].score > heap[largest].score) {
1225
- largest = left;
1226
- }
1227
- if (right < len && heap[right].score > heap[largest].score) {
1228
- largest = right;
1229
- }
981
+ if (left < len && this.comparator(heap[left], heap[largest]) > 0) largest = left;
982
+ if (right < len && this.comparator(heap[right], heap[largest]) > 0) largest = right;
1230
983
  if (largest !== i) {
1231
984
  const tmp = heap[i];
1232
985
  heap[i] = heap[largest];
@@ -1234,201 +987,223 @@
1234
987
  }
1235
988
  } while (largest !== i);
1236
989
  }
1237
- }
1238
- function transformMatches(result, data) {
1239
- const matches = result.matches;
1240
- data.matches = [];
1241
- if (!isDefined(matches)) {
1242
- return;
1243
- }
1244
- matches.forEach((match) => {
1245
- if (!isDefined(match.indices) || !match.indices.length) {
1246
- return;
1247
- }
1248
- const {
1249
- indices,
1250
- value
1251
- } = match;
990
+ };
991
+ function formatMatches(result) {
992
+ const matches = [];
993
+ result.matches.forEach((match) => {
994
+ if (!isDefined(match.indices) || !match.indices.length) return;
1252
995
  const obj = {
1253
- indices,
1254
- value
996
+ indices: match.indices,
997
+ value: match.value
1255
998
  };
1256
- if (match.key) {
1257
- obj.key = match.key.src;
1258
- }
1259
- if (match.idx > -1) {
1260
- obj.refIndex = match.idx;
1261
- }
1262
- data.matches.push(obj);
999
+ if (match.key) obj.key = match.key.id;
1000
+ if (match.idx > -1) obj.refIndex = match.idx;
1001
+ matches.push(obj);
1263
1002
  });
1003
+ return matches;
1264
1004
  }
1265
- function transformScore(result, data) {
1266
- data.score = result.score;
1267
- }
1268
- function format(results, docs, {
1269
- includeMatches = Config.includeMatches,
1270
- includeScore = Config.includeScore
1271
- } = {}) {
1272
- const transformers = [];
1273
- if (includeMatches) transformers.push(transformMatches);
1274
- if (includeScore) transformers.push(transformScore);
1005
+ function format(results, docs, { includeMatches = Config.includeMatches, includeScore = Config.includeScore } = {}) {
1275
1006
  return results.map((result) => {
1276
- const {
1277
- idx
1278
- } = result;
1007
+ const { idx } = result;
1279
1008
  const data = {
1280
1009
  item: docs[idx],
1281
1010
  refIndex: idx
1282
1011
  };
1283
- if (transformers.length) {
1284
- transformers.forEach((transformer) => {
1285
- transformer(result, data);
1286
- });
1287
- }
1012
+ if (includeMatches) data.matches = formatMatches(result);
1013
+ if (includeScore) data.score = result.score;
1288
1014
  return data;
1289
1015
  });
1290
1016
  }
1291
- const WORD = /\b\w+\b/g;
1292
- function createAnalyzer({
1293
- isCaseSensitive = false,
1294
- ignoreDiacritics = false
1295
- } = {}) {
1296
- return {
1297
- tokenize(text) {
1298
- if (!isCaseSensitive) {
1299
- text = text.toLowerCase();
1300
- }
1301
- if (ignoreDiacritics) {
1302
- text = stripDiacritics(text);
1303
- }
1304
- return text.match(WORD) || [];
1305
- }
1306
- };
1017
+ const DEFAULT_TOKEN = /[\p{L}\p{M}\p{N}_]+/gu;
1018
+ const warned = /* @__PURE__ */ new WeakSet();
1019
+ function warnNonGlobal(regex) {
1020
+ if (!warned.has(regex)) {
1021
+ warned.add(regex);
1022
+ console.warn(`[Fuse] tokenize regex ${regex} lacks the global flag; only the first match per text will be returned. Add the 'g' flag.`);
1023
+ }
1307
1024
  }
1308
- function buildInvertedIndex(records, keyCount, analyzer) {
1309
- const terms = /* @__PURE__ */ new Map();
1310
- const df = /* @__PURE__ */ new Map();
1311
- let fieldCount = 0;
1312
- function addField(text, docIdx, keyIdx, subIdx) {
1313
- const tokens = analyzer.tokenize(text);
1314
- if (!tokens.length) return;
1315
- fieldCount++;
1316
- const termFreqs = /* @__PURE__ */ new Map();
1317
- for (const token of tokens) {
1318
- termFreqs.set(token, (termFreqs.get(token) || 0) + 1);
1319
- }
1320
- for (const [term, tf] of termFreqs) {
1321
- const posting = {
1322
- docIdx,
1323
- keyIdx,
1324
- subIdx,
1325
- tf
1326
- };
1327
- let postings = terms.get(term);
1328
- if (!postings) {
1329
- postings = [];
1330
- terms.set(term, postings);
1025
+ function resolveTokenize(tokenize2) {
1026
+ if (typeof tokenize2 === "function") {
1027
+ let validated = false;
1028
+ return (text) => {
1029
+ const result = tokenize2(text);
1030
+ if (!validated) {
1031
+ validated = true;
1032
+ if (!Array.isArray(result) || result.some((t) => typeof t !== "string")) throw new Error(`[Fuse] tokenize function must return string[]; received ${Array.isArray(result) ? "array containing non-strings" : typeof result}.`);
1331
1033
  }
1332
- postings.push(posting);
1333
- df.set(term, (df.get(term) || 0) + 1);
1334
- }
1034
+ return result;
1035
+ };
1335
1036
  }
1336
- for (const record of records) {
1337
- const {
1338
- i: docIdx,
1339
- v,
1340
- $: fields
1341
- } = record;
1342
- if (v !== void 0) {
1343
- addField(v, docIdx, -1, -1);
1344
- continue;
1345
- }
1346
- if (fields) {
1347
- for (let keyIdx = 0; keyIdx < keyCount; keyIdx++) {
1348
- const value = fields[keyIdx];
1349
- if (!value) continue;
1350
- if (Array.isArray(value)) {
1351
- for (const sub of value) {
1352
- addField(sub.v, docIdx, keyIdx, sub.i ?? -1);
1353
- }
1354
- } else {
1355
- addField(value.v, docIdx, keyIdx, -1);
1356
- }
1357
- }
1358
- }
1037
+ if (tokenize2 instanceof RegExp) {
1038
+ if (!tokenize2.global) warnNonGlobal(tokenize2);
1039
+ return (text) => text.match(tokenize2) || [];
1359
1040
  }
1360
- return {
1361
- terms,
1362
- fieldCount,
1363
- df
1364
- };
1041
+ return (text) => text.match(DEFAULT_TOKEN) || [];
1365
1042
  }
1366
- function addToInvertedIndex(index, record, keyCount, analyzer) {
1367
- const {
1368
- i: docIdx,
1369
- v,
1370
- $: fields
1371
- } = record;
1372
- function addField(text, keyIdx, subIdx) {
1373
- const tokens = analyzer.tokenize(text);
1374
- if (!tokens.length) return;
1375
- index.fieldCount++;
1376
- const termFreqs = /* @__PURE__ */ new Map();
1377
- for (const token of tokens) {
1378
- termFreqs.set(token, (termFreqs.get(token) || 0) + 1);
1043
+ function createAnalyzer({ isCaseSensitive = false, ignoreDiacritics = false, tokenize: tokenize2 } = {}) {
1044
+ const tokenizeFn = resolveTokenize(tokenize2);
1045
+ return { tokenize(text) {
1046
+ if (!isCaseSensitive) text = text.toLowerCase();
1047
+ if (ignoreDiacritics) text = stripDiacritics(text);
1048
+ return tokenizeFn(text);
1049
+ } };
1050
+ }
1051
+ var TokenSearch = class {
1052
+ static condition(_, options) {
1053
+ return options.useTokenSearch;
1054
+ }
1055
+ constructor(pattern, options) {
1056
+ this.options = options;
1057
+ this.analyzer = createAnalyzer({
1058
+ isCaseSensitive: options.isCaseSensitive,
1059
+ ignoreDiacritics: options.ignoreDiacritics,
1060
+ tokenize: options.tokenize
1061
+ });
1062
+ const queryTerms = this.analyzer.tokenize(pattern);
1063
+ const { df, fieldCount } = options._invertedIndex;
1064
+ this.termSearchers = [];
1065
+ this.idfWeights = [];
1066
+ for (const term of queryTerms) {
1067
+ this.termSearchers.push(new BitapSearch(term, {
1068
+ location: options.location,
1069
+ threshold: options.threshold,
1070
+ distance: options.distance,
1071
+ includeMatches: options.includeMatches,
1072
+ findAllMatches: options.findAllMatches,
1073
+ minMatchCharLength: options.minMatchCharLength,
1074
+ isCaseSensitive: options.isCaseSensitive,
1075
+ ignoreDiacritics: options.ignoreDiacritics,
1076
+ ignoreLocation: true
1077
+ }));
1078
+ const docFreq = df.get(term) || 0;
1079
+ const idf = Math.log(1 + (fieldCount - docFreq + 0.5) / (docFreq + 0.5));
1080
+ this.idfWeights.push(idf);
1379
1081
  }
1380
- for (const [term, tf] of termFreqs) {
1381
- const posting = {
1382
- docIdx,
1383
- keyIdx,
1384
- subIdx,
1385
- tf
1386
- };
1387
- let postings = index.terms.get(term);
1388
- if (!postings) {
1389
- postings = [];
1390
- index.terms.set(term, postings);
1082
+ this.combineAll = options.tokenMatch === "all";
1083
+ this.numTerms = this.termSearchers.length;
1084
+ this.useMask = this.numTerms <= 31;
1085
+ }
1086
+ searchIn(text) {
1087
+ if (!this.termSearchers.length) return {
1088
+ isMatch: false,
1089
+ score: 1
1090
+ };
1091
+ const allIndices = [];
1092
+ let weightedScore = 0;
1093
+ let maxPossibleScore = 0;
1094
+ let matchedCount = 0;
1095
+ let matchedMask = 0;
1096
+ const matchedTerms = this.combineAll && !this.useMask ? /* @__PURE__ */ new Set() : null;
1097
+ for (let i = 0; i < this.termSearchers.length; i++) {
1098
+ const result = this.termSearchers[i].searchIn(text);
1099
+ const idf = this.idfWeights[i];
1100
+ maxPossibleScore += idf;
1101
+ if (result.isMatch) {
1102
+ matchedCount++;
1103
+ weightedScore += idf * (1 - result.score);
1104
+ if (result.indices) allIndices.push(...result.indices);
1105
+ if (this.combineAll) if (this.useMask) matchedMask |= 1 << i;
1106
+ else matchedTerms.add(i);
1391
1107
  }
1392
- postings.push(posting);
1393
- index.df.set(term, (index.df.get(term) || 0) + 1);
1394
1108
  }
1109
+ if (matchedCount === 0) return {
1110
+ isMatch: false,
1111
+ score: 1
1112
+ };
1113
+ const normalized = maxPossibleScore > 0 ? 1 - weightedScore / maxPossibleScore : 0;
1114
+ const searchResult = {
1115
+ isMatch: true,
1116
+ score: Math.max(1e-3, normalized)
1117
+ };
1118
+ if (this.options.includeMatches && allIndices.length) searchResult.indices = mergeIndices(allIndices);
1119
+ if (this.combineAll) {
1120
+ if (this.useMask) searchResult.matchedMask = matchedMask;
1121
+ else searchResult.matchedTerms = matchedTerms;
1122
+ searchResult.termCount = this.numTerms;
1123
+ }
1124
+ return searchResult;
1125
+ }
1126
+ };
1127
+ function addField(index, text, docIdx, analyzer) {
1128
+ const tokens = analyzer.tokenize(text);
1129
+ if (!tokens.length) return;
1130
+ index.fieldCount++;
1131
+ index.docFieldCount.set(docIdx, (index.docFieldCount.get(docIdx) || 0) + 1);
1132
+ const distinctTerms = new Set(tokens);
1133
+ let perDocTerms = index.docTermFieldHits.get(docIdx);
1134
+ if (!perDocTerms) {
1135
+ perDocTerms = /* @__PURE__ */ new Map();
1136
+ index.docTermFieldHits.set(docIdx, perDocTerms);
1137
+ }
1138
+ for (const term of distinctTerms) {
1139
+ perDocTerms.set(term, (perDocTerms.get(term) || 0) + 1);
1140
+ index.df.set(term, (index.df.get(term) || 0) + 1);
1395
1141
  }
1142
+ }
1143
+ function ingestRecord(index, record, keyCount, analyzer) {
1144
+ const { i: docIdx, v, $: fields } = record;
1396
1145
  if (v !== void 0) {
1397
- addField(v, -1, -1);
1146
+ addField(index, v, docIdx, analyzer);
1398
1147
  return;
1399
1148
  }
1400
- if (fields) {
1401
- for (let keyIdx = 0; keyIdx < keyCount; keyIdx++) {
1402
- const value = fields[keyIdx];
1403
- if (!value) continue;
1404
- if (Array.isArray(value)) {
1405
- for (const sub of value) {
1406
- addField(sub.v, keyIdx, sub.i ?? -1);
1407
- }
1408
- } else {
1409
- addField(value.v, keyIdx, -1);
1410
- }
1411
- }
1149
+ if (!fields) return;
1150
+ for (let keyIdx = 0; keyIdx < keyCount; keyIdx++) {
1151
+ const value = fields[keyIdx];
1152
+ if (!value) continue;
1153
+ if (Array.isArray(value)) for (const sub of value) addField(index, sub.v, docIdx, analyzer);
1154
+ else addField(index, value.v, docIdx, analyzer);
1412
1155
  }
1413
1156
  }
1157
+ function buildInvertedIndex(records, keyCount, analyzer) {
1158
+ const index = {
1159
+ fieldCount: 0,
1160
+ df: /* @__PURE__ */ new Map(),
1161
+ docFieldCount: /* @__PURE__ */ new Map(),
1162
+ docTermFieldHits: /* @__PURE__ */ new Map()
1163
+ };
1164
+ for (const record of records) ingestRecord(index, record, keyCount, analyzer);
1165
+ return index;
1166
+ }
1167
+ function addToInvertedIndex(index, record, keyCount, analyzer) {
1168
+ ingestRecord(index, record, keyCount, analyzer);
1169
+ }
1414
1170
  function removeFromInvertedIndex(index, docIdx) {
1415
- for (const [term, postings] of index.terms) {
1416
- const filtered = postings.filter((p) => p.docIdx !== docIdx);
1417
- const removed = postings.length - filtered.length;
1418
- if (removed > 0) {
1419
- index.fieldCount -= removed;
1420
- index.df.set(term, (index.df.get(term) || 0) - removed);
1421
- if (filtered.length === 0) {
1422
- index.terms.delete(term);
1423
- index.df.delete(term);
1424
- } else {
1425
- index.terms.set(term, filtered);
1426
- }
1427
- }
1428
- }
1171
+ const fieldCount = index.docFieldCount.get(docIdx);
1172
+ if (fieldCount === void 0) return;
1173
+ index.fieldCount -= fieldCount;
1174
+ index.docFieldCount.delete(docIdx);
1175
+ const perDocTerms = index.docTermFieldHits.get(docIdx);
1176
+ if (!perDocTerms) return;
1177
+ for (const [term, hits] of perDocTerms) {
1178
+ const next = (index.df.get(term) || 0) - hits;
1179
+ if (next <= 0) index.df.delete(term);
1180
+ else index.df.set(term, next);
1181
+ }
1182
+ index.docTermFieldHits.delete(docIdx);
1429
1183
  }
1430
- class Fuse {
1431
- // Statics are assigned in entry.ts
1184
+ function removeAndShiftInvertedIndex(index, removedIndices) {
1185
+ if (removedIndices.length === 0) return;
1186
+ const sorted = Array.from(new Set(removedIndices)).sort((a, b) => a - b);
1187
+ for (const idx of sorted) removeFromInvertedIndex(index, idx);
1188
+ const shift = (oldIdx) => {
1189
+ let lo = 0;
1190
+ let hi = sorted.length;
1191
+ while (lo < hi) {
1192
+ const mid = lo + hi >>> 1;
1193
+ if (sorted[mid] < oldIdx) lo = mid + 1;
1194
+ else hi = mid;
1195
+ }
1196
+ return oldIdx - lo;
1197
+ };
1198
+ const firstRemoved = sorted[0];
1199
+ const shiftedDocFieldCount = /* @__PURE__ */ new Map();
1200
+ for (const [oldKey, count] of index.docFieldCount) shiftedDocFieldCount.set(oldKey > firstRemoved ? shift(oldKey) : oldKey, count);
1201
+ index.docFieldCount = shiftedDocFieldCount;
1202
+ const shiftedDocTermFieldHits = /* @__PURE__ */ new Map();
1203
+ for (const [oldKey, terms] of index.docTermFieldHits) shiftedDocTermFieldHits.set(oldKey > firstRemoved ? shift(oldKey) : oldKey, terms);
1204
+ index.docTermFieldHits = shiftedDocTermFieldHits;
1205
+ }
1206
+ var Fuse = class {
1432
1207
  constructor(docs, options, index) {
1433
1208
  this.options = {
1434
1209
  ...Config,
@@ -1445,23 +1220,18 @@
1445
1220
  this._lastSearcher = null;
1446
1221
  }
1447
1222
  _getSearcher(query) {
1448
- if (this._lastQuery === query) {
1449
- return this._lastSearcher;
1450
- }
1451
- const opts = this._invertedIndex ? {
1223
+ if (this._lastQuery === query) return this._lastSearcher;
1224
+ const searcher = createSearcher(query, this._invertedIndex ? {
1452
1225
  ...this.options,
1453
1226
  _invertedIndex: this._invertedIndex
1454
- } : this.options;
1455
- const searcher = createSearcher(query, opts);
1227
+ } : this.options);
1456
1228
  this._lastQuery = query;
1457
1229
  this._lastSearcher = searcher;
1458
1230
  return searcher;
1459
1231
  }
1460
1232
  setCollection(docs, index) {
1461
1233
  this._docs = docs;
1462
- if (index && !(index instanceof FuseIndex)) {
1463
- throw new Error(INCORRECT_INDEX_TYPE);
1464
- }
1234
+ if (index && !(index instanceof FuseIndex)) throw new Error(INCORRECT_INDEX_TYPE);
1465
1235
  this._myIndex = index || createIndex(this.options.keys, this._docs, {
1466
1236
  getFn: this.options.getFn,
1467
1237
  fieldNormWeight: this.options.fieldNormWeight
@@ -1469,155 +1239,129 @@
1469
1239
  if (this.options.useTokenSearch) {
1470
1240
  const analyzer = createAnalyzer({
1471
1241
  isCaseSensitive: this.options.isCaseSensitive,
1472
- ignoreDiacritics: this.options.ignoreDiacritics
1242
+ ignoreDiacritics: this.options.ignoreDiacritics,
1243
+ tokenize: this.options.tokenize
1473
1244
  });
1474
1245
  this._invertedIndex = buildInvertedIndex(this._myIndex.records, this._myIndex.keys.length, analyzer);
1475
1246
  }
1247
+ this._invalidateSearcherCache();
1476
1248
  }
1477
1249
  add(doc) {
1478
- if (!isDefined(doc)) {
1479
- return;
1480
- }
1250
+ if (!isDefined(doc)) return;
1481
1251
  this._docs.push(doc);
1482
- this._myIndex.add(doc);
1483
- if (this._invertedIndex) {
1484
- const record = this._myIndex.records[this._myIndex.records.length - 1];
1252
+ const record = this._myIndex.add(doc, this._docs.length - 1);
1253
+ if (this._invertedIndex && record) {
1485
1254
  const analyzer = createAnalyzer({
1486
1255
  isCaseSensitive: this.options.isCaseSensitive,
1487
- ignoreDiacritics: this.options.ignoreDiacritics
1256
+ ignoreDiacritics: this.options.ignoreDiacritics,
1257
+ tokenize: this.options.tokenize
1488
1258
  });
1489
1259
  addToInvertedIndex(this._invertedIndex, record, this._myIndex.keys.length, analyzer);
1490
1260
  }
1261
+ this._invalidateSearcherCache();
1491
1262
  }
1492
1263
  remove(predicate = () => false) {
1493
1264
  const results = [];
1494
1265
  const indicesToRemove = [];
1495
- for (let i = 0, len = this._docs.length; i < len; i += 1) {
1496
- if (predicate(this._docs[i], i)) {
1497
- results.push(this._docs[i]);
1498
- indicesToRemove.push(i);
1499
- }
1266
+ for (let i = 0, len = this._docs.length; i < len; i += 1) if (predicate(this._docs[i], i)) {
1267
+ results.push(this._docs[i]);
1268
+ indicesToRemove.push(i);
1500
1269
  }
1501
1270
  if (indicesToRemove.length) {
1502
- if (this._invertedIndex) {
1503
- for (const idx of indicesToRemove) {
1504
- removeFromInvertedIndex(this._invertedIndex, idx);
1505
- }
1506
- }
1507
- for (let i = indicesToRemove.length - 1; i >= 0; i -= 1) {
1508
- this._docs.splice(indicesToRemove[i], 1);
1509
- }
1271
+ if (this._invertedIndex) removeAndShiftInvertedIndex(this._invertedIndex, indicesToRemove);
1272
+ const toRemove = new Set(indicesToRemove);
1273
+ this._docs = this._docs.filter((_, i) => !toRemove.has(i));
1510
1274
  this._myIndex.removeAll(indicesToRemove);
1275
+ this._invalidateSearcherCache();
1511
1276
  }
1512
1277
  return results;
1513
1278
  }
1514
1279
  removeAt(idx) {
1515
- if (this._invertedIndex) {
1516
- removeFromInvertedIndex(this._invertedIndex, idx);
1517
- }
1280
+ if (!Number.isInteger(idx) || idx < 0 || idx >= this._docs.length) throw new Error(INVALID_DOC_INDEX);
1281
+ if (this._invertedIndex) removeAndShiftInvertedIndex(this._invertedIndex, [idx]);
1518
1282
  const doc = this._docs.splice(idx, 1)[0];
1519
1283
  this._myIndex.removeAt(idx);
1284
+ this._invalidateSearcherCache();
1520
1285
  return doc;
1521
1286
  }
1287
+ _invalidateSearcherCache() {
1288
+ this._lastQuery = null;
1289
+ this._lastSearcher = null;
1290
+ }
1522
1291
  getIndex() {
1523
1292
  return this._myIndex;
1524
1293
  }
1294
+ _normalizedKeys() {
1295
+ return this._myIndex.keys.map((key) => this._keyStore.get(key.id) || key);
1296
+ }
1525
1297
  search(query, options) {
1526
- const {
1527
- limit = -1
1528
- } = options || {};
1529
- const {
1530
- includeMatches,
1531
- includeScore,
1532
- shouldSort,
1533
- sortFn,
1534
- ignoreFieldNorm
1535
- } = this.options;
1298
+ const { limit = -1 } = options || {};
1299
+ const { includeMatches, includeScore, shouldSort, sortFn, ignoreFieldNorm } = this.options;
1536
1300
  if (isString(query) && !query.trim()) {
1537
1301
  let docs = this._docs.map((item, idx) => ({
1538
1302
  item,
1539
1303
  refIndex: idx
1540
1304
  }));
1541
- if (isNumber(limit) && limit > -1) {
1542
- docs = docs.slice(0, limit);
1543
- }
1305
+ if (isNumber(limit) && limit > -1) docs = docs.slice(0, limit);
1544
1306
  return docs;
1545
1307
  }
1546
- const useHeap = isNumber(limit) && limit > 0 && isString(query);
1308
+ const useHeap = shouldSort && isNumber(limit) && limit > 0 && isString(query);
1309
+ const comparator = sortFn;
1310
+ const stable = (a, b) => comparator(a, b) || a.idx - b.idx;
1547
1311
  let results;
1548
1312
  if (useHeap) {
1549
- const heap = new MaxHeap(limit);
1550
- if (isString(this._docs[0])) {
1551
- this._searchStringList(query, {
1552
- heap,
1553
- ignoreFieldNorm
1554
- });
1555
- } else {
1556
- this._searchObjectList(query, {
1557
- heap,
1558
- ignoreFieldNorm
1559
- });
1560
- }
1561
- results = heap.extractSorted(sortFn);
1562
- } else {
1563
- results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);
1564
- computeScore(results, {
1313
+ const heap = new MaxHeap(limit, stable);
1314
+ if (isString(this._docs[0])) this._searchStringList(query, {
1315
+ heap,
1565
1316
  ignoreFieldNorm
1566
1317
  });
1567
- if (shouldSort) {
1568
- results.sort(sortFn);
1569
- }
1570
- if (isNumber(limit) && limit > -1) {
1571
- results = results.slice(0, limit);
1572
- }
1318
+ else this._searchObjectList(query, {
1319
+ heap,
1320
+ ignoreFieldNorm
1321
+ });
1322
+ results = heap.extractSorted();
1323
+ } else {
1324
+ results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);
1325
+ computeScore(results, { ignoreFieldNorm });
1326
+ if (shouldSort) results.sort(isString(query) ? stable : comparator);
1327
+ if (isNumber(limit) && limit > -1) results = results.slice(0, limit);
1573
1328
  }
1574
1329
  return format(results, this._docs, {
1575
1330
  includeMatches,
1576
1331
  includeScore
1577
1332
  });
1578
1333
  }
1579
- _searchStringList(query, {
1580
- heap,
1581
- ignoreFieldNorm
1582
- } = {}) {
1334
+ _searchStringList(query, { heap, ignoreFieldNorm } = {}) {
1583
1335
  const searcher = this._getSearcher(query);
1584
- const {
1585
- records
1586
- } = this._myIndex;
1336
+ const requireAllTokens = this.options.useTokenSearch && this.options.tokenMatch === "all";
1337
+ const { records } = this._myIndex;
1587
1338
  const results = heap ? null : [];
1588
- records.forEach(({
1589
- v: text,
1590
- i: idx,
1591
- n: norm2
1592
- }) => {
1593
- if (!isDefined(text)) {
1594
- return;
1595
- }
1596
- const {
1597
- isMatch,
1598
- score,
1599
- indices
1600
- } = searcher.searchIn(text);
1601
- if (isMatch) {
1602
- const result = {
1603
- item: text,
1604
- idx,
1605
- matches: [{
1606
- score,
1607
- value: text,
1608
- norm: norm2,
1609
- indices
1610
- }]
1339
+ records.forEach(({ v: text, i: idx, n: norm2 }) => {
1340
+ if (!isDefined(text)) return;
1341
+ const searchResult = searcher.searchIn(text);
1342
+ if (searchResult.isMatch) {
1343
+ const match = {
1344
+ score: searchResult.score,
1345
+ value: text,
1346
+ norm: norm2,
1347
+ indices: searchResult.indices
1611
1348
  };
1612
- if (heap) {
1613
- result.score = computeScoreSingle(result.matches, {
1614
- ignoreFieldNorm
1615
- });
1616
- if (heap.shouldInsert(result.score)) {
1349
+ if (requireAllTokens) {
1350
+ match.matchedMask = searchResult.matchedMask;
1351
+ match.matchedTerms = searchResult.matchedTerms;
1352
+ match.termCount = searchResult.termCount;
1353
+ }
1354
+ const matches = [match];
1355
+ if (!requireAllTokens || this._coversAllTokens(matches)) {
1356
+ const result = {
1357
+ item: text,
1358
+ idx,
1359
+ matches
1360
+ };
1361
+ if (heap) {
1362
+ result.score = computeScoreSingle(result.matches, { ignoreFieldNorm });
1617
1363
  heap.insert(result);
1618
- }
1619
- } else {
1620
- results.push(result);
1364
+ } else results.push(result);
1621
1365
  }
1622
1366
  }
1623
1367
  });
@@ -1625,61 +1369,46 @@
1625
1369
  }
1626
1370
  _searchLogical(query) {
1627
1371
  const expression = parse(query, this.options);
1372
+ const keys = this._normalizedKeys();
1628
1373
  const evaluate = (node, item, idx) => {
1629
1374
  if (!("children" in node)) {
1630
- const {
1631
- keyId,
1632
- searcher
1633
- } = node;
1375
+ const { keyId, searcher } = node;
1634
1376
  let matches;
1635
1377
  if (keyId === null) {
1636
1378
  matches = [];
1637
- this._myIndex.keys.forEach((key, keyIndex) => {
1379
+ keys.forEach((key, keyIndex) => {
1638
1380
  matches.push(...this._findMatches({
1639
1381
  key,
1640
1382
  value: item[keyIndex],
1641
1383
  searcher
1642
1384
  }));
1643
1385
  });
1644
- } else {
1645
- matches = this._findMatches({
1646
- key: this._keyStore.get(keyId),
1647
- value: this._myIndex.getValueForItemAtKeyId(item, keyId),
1648
- searcher
1649
- });
1650
- }
1651
- if (matches && matches.length) {
1652
- return [{
1653
- idx,
1654
- item,
1655
- matches
1656
- }];
1657
- }
1386
+ } else matches = this._findMatches({
1387
+ key: this._keyStore.get(keyId),
1388
+ value: this._myIndex.getValueForItemAtKeyId(item, keyId),
1389
+ searcher
1390
+ });
1391
+ if (matches && matches.length) return [{
1392
+ idx,
1393
+ item,
1394
+ matches
1395
+ }];
1658
1396
  return [];
1659
1397
  }
1660
- const {
1661
- children,
1662
- operator
1663
- } = node;
1398
+ const { children, operator } = node;
1664
1399
  const res = [];
1665
1400
  for (let i = 0, len = children.length; i < len; i += 1) {
1666
1401
  const child = children[i];
1667
1402
  const result = evaluate(child, item, idx);
1668
- if (result.length) {
1669
- res.push(...result);
1670
- } else if (operator === LogicalOperator.AND) {
1671
- return [];
1672
- }
1403
+ if (result.length) res.push(...result);
1404
+ else if (operator === LogicalOperator.AND) return [];
1673
1405
  }
1674
1406
  return res;
1675
1407
  };
1676
1408
  const records = this._myIndex.records;
1677
1409
  const resultMap = /* @__PURE__ */ new Map();
1678
1410
  const results = [];
1679
- records.forEach(({
1680
- $: item,
1681
- i: idx
1682
- }) => {
1411
+ records.forEach(({ $: item, i: idx }) => {
1683
1412
  if (isDefined(item)) {
1684
1413
  const expResults = evaluate(expression, item, idx);
1685
1414
  if (expResults.length) {
@@ -1691,9 +1420,7 @@
1691
1420
  });
1692
1421
  results.push(resultMap.get(idx));
1693
1422
  }
1694
- expResults.forEach(({
1695
- matches
1696
- }) => {
1423
+ expResults.forEach(({ matches }) => {
1697
1424
  resultMap.get(idx).matches.push(...matches);
1698
1425
  });
1699
1426
  }
@@ -1701,31 +1428,14 @@
1701
1428
  });
1702
1429
  return results;
1703
1430
  }
1704
- // When a search involves inverse patterns (e.g. !Syrup), the aggregation
1705
- // across keys switches from "ANY key matches" to "ALL keys must match."
1706
- // This is signaled by hasInverse on the SearchResult from ExtendedSearch.
1707
- //
1708
- // For mixed patterns like "^hello !Syrup", a key failure is ambiguous —
1709
- // it could be the positive or inverse term that failed. In that case we
1710
- // conservatively exclude the item, which is strictly better than the old
1711
- // behavior of including it. See: https://github.com/krisk/Fuse/issues/712
1712
- _searchObjectList(query, {
1713
- heap,
1714
- ignoreFieldNorm
1715
- } = {}) {
1431
+ _searchObjectList(query, { heap, ignoreFieldNorm } = {}) {
1716
1432
  const searcher = this._getSearcher(query);
1717
- const {
1718
- keys,
1719
- records
1720
- } = this._myIndex;
1433
+ const requireAllTokens = this.options.useTokenSearch && this.options.tokenMatch === "all";
1434
+ const { records } = this._myIndex;
1435
+ const keys = this._normalizedKeys();
1721
1436
  const results = heap ? null : [];
1722
- records.forEach(({
1723
- $: item,
1724
- i: idx
1725
- }) => {
1726
- if (!isDefined(item)) {
1727
- return;
1728
- }
1437
+ records.forEach(({ $: item, i: idx }) => {
1438
+ if (!isDefined(item)) return;
1729
1439
  const matches = [];
1730
1440
  let anyKeyFailed = false;
1731
1441
  let hasInverse = false;
@@ -1737,195 +1447,104 @@
1737
1447
  });
1738
1448
  if (keyMatches.length) {
1739
1449
  matches.push(...keyMatches);
1740
- if (keyMatches[0].hasInverse) {
1741
- hasInverse = true;
1742
- }
1743
- } else {
1744
- anyKeyFailed = true;
1745
- }
1450
+ if (keyMatches[0].hasInverse) hasInverse = true;
1451
+ } else anyKeyFailed = true;
1746
1452
  });
1747
- if (hasInverse && anyKeyFailed) {
1748
- return;
1749
- }
1750
- if (matches.length) {
1453
+ if (hasInverse && anyKeyFailed) return;
1454
+ if (matches.length && (!requireAllTokens || this._coversAllTokens(matches))) {
1751
1455
  const result = {
1752
1456
  idx,
1753
1457
  item,
1754
1458
  matches
1755
1459
  };
1756
1460
  if (heap) {
1757
- result.score = computeScoreSingle(result.matches, {
1758
- ignoreFieldNorm
1759
- });
1760
- if (heap.shouldInsert(result.score)) {
1761
- heap.insert(result);
1762
- }
1763
- } else {
1764
- results.push(result);
1765
- }
1461
+ result.score = computeScoreSingle(result.matches, { ignoreFieldNorm });
1462
+ heap.insert(result);
1463
+ } else results.push(result);
1766
1464
  }
1767
1465
  });
1768
1466
  return results;
1769
1467
  }
1770
- _findMatches({
1771
- key,
1772
- value,
1773
- searcher
1774
- }) {
1775
- if (!isDefined(value)) {
1776
- return [];
1777
- }
1468
+ _findMatches({ key, value, searcher }) {
1469
+ if (!isDefined(value)) return [];
1778
1470
  const matches = [];
1779
- if (isArray(value)) {
1780
- value.forEach(({
1781
- v: text,
1782
- i: idx,
1783
- n: norm2
1784
- }) => {
1785
- if (!isDefined(text)) {
1786
- return;
1787
- }
1788
- const {
1789
- isMatch,
1790
- score,
1791
- indices,
1792
- hasInverse
1793
- } = searcher.searchIn(text);
1794
- if (isMatch) {
1795
- matches.push({
1796
- score,
1797
- key,
1798
- value: text,
1799
- idx,
1800
- norm: norm2,
1801
- indices,
1802
- hasInverse
1803
- });
1804
- }
1805
- });
1806
- } else {
1807
- const {
1808
- v: text,
1809
- n: norm2
1810
- } = value;
1811
- const {
1812
- isMatch,
1813
- score,
1814
- indices,
1815
- hasInverse
1816
- } = searcher.searchIn(text);
1817
- if (isMatch) {
1818
- matches.push({
1819
- score,
1471
+ if (isArray(value)) value.forEach(({ v: text, i: idx, n: norm2 }) => {
1472
+ if (!isDefined(text)) return;
1473
+ const searchResult = searcher.searchIn(text);
1474
+ if (searchResult.isMatch) {
1475
+ const match = {
1476
+ score: searchResult.score,
1820
1477
  key,
1821
1478
  value: text,
1479
+ idx,
1822
1480
  norm: norm2,
1823
- indices,
1824
- hasInverse
1825
- });
1481
+ indices: searchResult.indices,
1482
+ hasInverse: searchResult.hasInverse
1483
+ };
1484
+ if (searchResult.termCount !== void 0) {
1485
+ match.matchedMask = searchResult.matchedMask;
1486
+ match.matchedTerms = searchResult.matchedTerms;
1487
+ match.termCount = searchResult.termCount;
1488
+ }
1489
+ matches.push(match);
1826
1490
  }
1827
- }
1828
- return matches;
1829
- }
1830
- }
1831
- class TokenSearch {
1832
- static condition(_, options) {
1833
- return options.useTokenSearch;
1834
- }
1835
- constructor(pattern, options) {
1836
- this.options = options;
1837
- this.analyzer = createAnalyzer({
1838
- isCaseSensitive: options.isCaseSensitive,
1839
- ignoreDiacritics: options.ignoreDiacritics
1840
1491
  });
1841
- const queryTerms = this.analyzer.tokenize(pattern);
1842
- const invertedIndex = options._invertedIndex;
1843
- const {
1844
- df,
1845
- fieldCount
1846
- } = invertedIndex;
1847
- this.termSearchers = [];
1848
- this.idfWeights = [];
1849
- for (const term of queryTerms) {
1850
- this.termSearchers.push(new BitapSearch(term, {
1851
- location: options.location,
1852
- threshold: options.threshold,
1853
- distance: options.distance,
1854
- includeMatches: options.includeMatches,
1855
- findAllMatches: options.findAllMatches,
1856
- minMatchCharLength: options.minMatchCharLength,
1857
- isCaseSensitive: options.isCaseSensitive,
1858
- ignoreDiacritics: options.ignoreDiacritics,
1859
- ignoreLocation: true
1860
- }));
1861
- const docFreq = df.get(term) || 0;
1862
- const idf = Math.log(1 + (fieldCount - docFreq + 0.5) / (docFreq + 0.5));
1863
- this.idfWeights.push(idf);
1864
- }
1865
- }
1866
- searchIn(text) {
1867
- if (!this.termSearchers.length) {
1868
- return {
1869
- isMatch: false,
1870
- score: 1
1871
- };
1872
- }
1873
- const allIndices = [];
1874
- let weightedScore = 0;
1875
- let maxPossibleScore = 0;
1876
- let matchedCount = 0;
1877
- for (let i = 0; i < this.termSearchers.length; i++) {
1878
- const result = this.termSearchers[i].searchIn(text);
1879
- const idf = this.idfWeights[i];
1880
- maxPossibleScore += idf;
1881
- if (result.isMatch) {
1882
- matchedCount++;
1883
- weightedScore += idf * (1 - result.score);
1884
- if (result.indices) {
1885
- allIndices.push(...result.indices);
1492
+ else {
1493
+ const { v: text, n: norm2 } = value;
1494
+ const searchResult = searcher.searchIn(text);
1495
+ if (searchResult.isMatch) {
1496
+ const match = {
1497
+ score: searchResult.score,
1498
+ key,
1499
+ value: text,
1500
+ norm: norm2,
1501
+ indices: searchResult.indices,
1502
+ hasInverse: searchResult.hasInverse
1503
+ };
1504
+ if (searchResult.termCount !== void 0) {
1505
+ match.matchedMask = searchResult.matchedMask;
1506
+ match.matchedTerms = searchResult.matchedTerms;
1507
+ match.termCount = searchResult.termCount;
1886
1508
  }
1509
+ matches.push(match);
1887
1510
  }
1888
1511
  }
1889
- if (matchedCount === 0) {
1890
- return {
1891
- isMatch: false,
1892
- score: 1
1893
- };
1512
+ return matches;
1513
+ }
1514
+ _coversAllTokens(matches) {
1515
+ const termCount = matches.length ? matches[0].termCount : void 0;
1516
+ if (termCount === void 0) return true;
1517
+ if (termCount <= 31) {
1518
+ let coverage2 = 0;
1519
+ for (let i = 0; i < matches.length; i++) coverage2 |= matches[i].matchedMask || 0;
1520
+ return coverage2 === 2 ** termCount - 1;
1894
1521
  }
1895
- const normalized = maxPossibleScore > 0 ? 1 - weightedScore / maxPossibleScore : 0;
1896
- const searchResult = {
1897
- isMatch: true,
1898
- score: Math.max(1e-3, normalized)
1899
- };
1900
- if (this.options.includeMatches && allIndices.length) {
1901
- searchResult.indices = mergeIndices(allIndices);
1522
+ const coverage = /* @__PURE__ */ new Set();
1523
+ for (let i = 0; i < matches.length; i++) {
1524
+ const terms = matches[i].matchedTerms;
1525
+ if (terms) for (const t of terms) coverage.add(t);
1902
1526
  }
1903
- return searchResult;
1527
+ return coverage.size === termCount;
1904
1528
  }
1905
- }
1906
- Fuse.version = "7.3.0";
1529
+ };
1530
+ Fuse.version = "7.5.0";
1907
1531
  Fuse.createIndex = createIndex;
1908
1532
  Fuse.parseIndex = parseIndex;
1909
1533
  Fuse.config = Config;
1910
1534
  Fuse.match = function(pattern, text, options) {
1911
- const searcher = createSearcher(pattern, {
1535
+ if (options && options.useTokenSearch) throw new Error(FUSE_MATCH_TOKEN_SEARCH_UNSUPPORTED);
1536
+ return createSearcher(pattern, {
1912
1537
  ...Config,
1913
1538
  ...options
1914
- });
1915
- return searcher.searchIn(text);
1539
+ }).searchIn(text);
1916
1540
  };
1917
- {
1918
- Fuse.parseQuery = parse;
1919
- }
1920
- {
1921
- register(ExtendedSearch);
1922
- }
1923
- {
1924
- register(TokenSearch);
1925
- }
1541
+ Fuse.parseQuery = parse;
1542
+ register(ExtendedSearch);
1543
+ register(TokenSearch);
1926
1544
  Fuse.use = function(...plugins) {
1927
1545
  plugins.forEach((plugin) => register(plugin));
1928
1546
  };
1547
+ var entry_default = Fuse;
1929
1548
  const version = "0.3.5";
1930
1549
  const packageJson = {
1931
1550
  version
@@ -2090,7 +1709,7 @@
2090
1709
  });
2091
1710
  }
2092
1711
  const search2 = (entities) => {
2093
- const fuse = new Fuse(entities, {
1712
+ const fuse = new entry_default(entities, {
2094
1713
  shouldSort: false,
2095
1714
  isCaseSensitive: false,
2096
1715
  findAllMatches: true,