Skip to content

Commit ed7867a

Browse files
authored
fix(search): fold -ie plurals in the Jira partial-match term key (#8991)
The singular key mapped -ies to -y, so movies keyed to 'movy' while movie stayed 'movie' and the half-the-terms floor missed a pair Jira's stemmed search treats as one word. As in the Porter stemmer, a final -y and -ie(s) now fold to i (policy/policies -> polici, movie/movies -> movi), which also makes the separate -ies branch unnecessary.
1 parent 84fc3af commit ed7867a

2 files changed

Lines changed: 13 additions & 4 deletions

File tree

‎apps/sim/lib/sim-search/live/text-match.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ describe('text match clauses', () => {
7979
expect(holdsHalfTheTerms('databases releases checklist owner')('Database release')).toBe(true)
8080
})
8181

82+
it('folds -ies plurals of both -y and -ie words, as the Porter stemmer does', () => {
83+
expect(holdsHalfTheTerms('movies rotation schedule owner')('Movie rotation')).toBe(true)
84+
expect(holdsHalfTheTerms('policies review schedule owner')('Policy review')).toBe(true)
85+
})
86+
8287
it('matches a term with punctuation inside it as written', () => {
8388
expect(holdsHalfTheTerms('ci/cd pipeline failure owner')('CI/CD pipeline')).toBe(true)
8489
})

‎apps/sim/lib/sim-search/live/text-match.ts‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,16 @@ function distinctTerms(query: string, keyOf: (term: string) => string): string[]
7272
.slice(0, MAX_ANY_TERMS)
7373
}
7474

75-
/** One key for a word and its regular plural (`token`/`tokens`, `process`/`processes`). */
75+
/**
76+
* One key for a word and its regular plural (`token`/`tokens`, `process`/`processes`). As in the
77+
* Porter stemmer, a final `-y` and `-ie(s)` fold to `i`, so `policy`/`policies` and
78+
* `movie`/`movies` each share a key.
79+
*/
7680
function singularKey(term: string): string {
7781
const key = term.toLowerCase()
78-
if (key.length > 4 && key.endsWith('ies')) return `${key.slice(0, -3)}y`
79-
const stem = /[^su]s$/.test(key) ? key.slice(0, -1) : key
80-
return /(?:s|x|z|ch|sh)e$/.test(stem) ? stem.slice(0, -1) : stem
82+
const stripped = /[^su]s$/.test(key) ? key.slice(0, -1) : key
83+
const stem = /(?:s|x|z|ch|sh|i)e$/.test(stripped) ? stripped.slice(0, -1) : stripped
84+
return stem.replace(/y$/, 'i')
8185
}
8286

8387
/** Escapes a value for a quoted JQL or CQL string, treating Lucene operators as literal text. */

0 commit comments

Comments
 (0)