Skip to content

fix(bitap): respect minMatchCharLength in exact-match shortcut#832

Closed
JSap0914 wants to merge 2 commits into
krisk:mainfrom
JSap0914:fix/exact-match-min-match-char-length
Closed

fix(bitap): respect minMatchCharLength in exact-match shortcut#832
JSap0914 wants to merge 2 commits into
krisk:mainfrom
JSap0914:fix/exact-match-min-match-char-length

Conversation

@JSap0914

Copy link
Copy Markdown
Contributor

Problem

The fast-path in BitapSearch.searchIn() for pattern === text (exact string equality) returned isMatch: true without checking minMatchCharLength. The non-exact bitap path enforces this option via convertMaskToIndices, but the shortcut bypassed it entirely.

Reproduction:

// Fuse.match
const r = Fuse.match('abc', 'abc', { minMatchCharLength: 5 })
console.log(r.isMatch) // BUG: true — 3 chars < minMatchCharLength 5

// Corpus search
const fuse = new Fuse(['abc', 'abcde12345'], { minMatchCharLength: 5 })
console.log(fuse.search('abc').map(r => r.item))
// BUG: ['abc'] — should be excluded (3 chars < 5)

Closes #831

Fix

Added a length guard in the exact-match branch of BitapSearch.searchIn():

if (text.length < this.options.minMatchCharLength) {
  return { isMatch: false, score: 1 }
}

This mirrors what convertMaskToIndices does in the non-exact path.

Verification

npx vitest run
# 374 passed (0 failed)
# 3 new tests added (2 Fuse.match + 1 corpus search); 0 existing tests modified

AI-assisted: this fix was developed with AI pair-programming support.

The fast-path for pattern === text in BitapSearch.searchIn() returned
isMatch: true unconditionally, bypassing the minMatchCharLength guard
that the non-exact bitap path enforces via convertMaskToIndices.

Add a length check that mirrors the bitap path behaviour: when the
entire matched region (= text.length for an exact match) is shorter
than minMatchCharLength, return isMatch: false with score 1.

Closes krisk#831
Copilot AI review requested due to automatic review settings June 27, 2026 12:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@krisk

krisk commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Nice catch, and the diagnosis on #831 is right.

I can't merge it as-is though. The tests import from dist/, and the dist/ in this PR doesn't have the guard. The "remove committed dist build artifacts" commit rebuilt the bundle without the fix (it got smaller, not bigger), so dist/fuse.mjs still has the old exact-match branch. On a clean checkout the two new Fuse.match/search tests fail against that stale bundle, so the 374-passed result doesn't reproduce here.

I've landed the same guard on main in dbb98b6 with dist/ rebuilt, plus a couple extra cases (empty-string match, token-search path). Going to close this in favor of that, but the credit's yours.

@krisk krisk closed this Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: exact-match shortcut in BitapSearch bypasses minMatchCharLength

3 participants