Skip to content

Commit 3959d91

Browse files
committed
fix(match): explicitly reject useTokenSearch in Fuse.match
Token search needs corpus statistics (df, fieldCount) that a one-off string comparison can't provide. Behavior used to diverge by build: - Full build: TokenSearch destructured `options._invertedIndex` and crashed with an opaque TypeError. - Basic build: TokenSearch isn't registered, so createSearcher silently fell back to BitapSearch and returned a normal fuzzy match — quietly divergent from the full build. Guard `useTokenSearch` directly in Fuse.match before calling createSearcher, so both builds throw the same explicit error. Plan 007.
1 parent d571390 commit 3959d91

3 files changed

Lines changed: 34 additions & 0 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ const result = Fuse.match('javscript', 'JavaScript: The Good Parts')
174174
// → { isMatch: true, score: 0.04, indices: [[0, 9]] }
175175
```
176176

177+
`Fuse.match()` does **not** support `useTokenSearch` — token search requires corpus-level statistics (`df`, `fieldCount`) that a one-off string comparison can't provide. Passing `useTokenSearch: true` throws an explicit error. Use `new Fuse(docs, { useTokenSearch: true }).search(query)` for token-search behavior.
178+
177179
### Dynamic Collections
178180

179181
Add and remove documents from a live index without rebuilding.

src/entry.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,22 @@ import { parse } from './core/queryParser'
55
import { ExtendedSearch } from './search'
66
import TokenSearch from './search/token'
77
import register, { createSearcher } from './core/register'
8+
import * as ErrorMsg from './core/errorMessages'
89

910
Fuse.version = '__VERSION__'
1011
Fuse.createIndex = createIndex
1112
Fuse.parseIndex = parseIndex
1213
Fuse.config = Config
1314

1415
Fuse.match = function (pattern: string, text: string, options?: any) {
16+
// Token search needs corpus statistics (df, fieldCount) that a one-off
17+
// string comparison can't provide. Reject it here so the contract is the
18+
// same in the full and basic builds — without this guard, the full build
19+
// crashes with an opaque TypeError and the basic build silently falls back
20+
// to fuzzy matching.
21+
if (options && options.useTokenSearch) {
22+
throw new Error(ErrorMsg.FUSE_MATCH_TOKEN_SEARCH_UNSUPPORTED)
23+
}
1524
const searcher = createSearcher(pattern, { ...Config, ...options })
1625
return searcher.searchIn(text)
1726
}

test/match.test.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import Fuse from '../dist/fuse.mjs'
2+
import FuseBasic from '../dist/fuse.basic.mjs'
3+
import * as ErrorMsg from '../src/core/errorMessages'
24

35
describe('Fuse.match', () => {
46
test('returns a match for a fuzzy match', () => {
@@ -59,4 +61,25 @@ describe('Fuse.match', () => {
5961
expect(end - start + 1).toBeGreaterThanOrEqual(3)
6062
})
6163
})
64+
65+
// Token search needs corpus-level statistics (df, fieldCount) that a one-off
66+
// string comparison can't provide. Both builds must reject it explicitly —
67+
// the full build used to crash with an opaque TypeError, the basic build
68+
// used to silently fall back to plain fuzzy matching.
69+
test('throws when useTokenSearch is true (full build)', () => {
70+
expect(() =>
71+
Fuse.match('apple', 'apple pie', { useTokenSearch: true })
72+
).toThrowError(ErrorMsg.FUSE_MATCH_TOKEN_SEARCH_UNSUPPORTED)
73+
})
74+
75+
test('throws when useTokenSearch is true (basic build)', () => {
76+
expect(() =>
77+
FuseBasic.match('apple', 'apple pie', { useTokenSearch: true })
78+
).toThrowError(ErrorMsg.FUSE_MATCH_TOKEN_SEARCH_UNSUPPORTED)
79+
})
80+
81+
test('still works when useTokenSearch is explicitly false', () => {
82+
const result = Fuse.match('apple', 'apple pie', { useTokenSearch: false })
83+
expect(result.isMatch).toBe(true)
84+
})
6285
})

0 commit comments

Comments
 (0)