(term: string)
| 83 | * Stems are used as PREFIX matches in FTS, so they don't need to be perfect English words. |
| 84 | */ |
| 85 | export function getStemVariants(term: string): string[] { |
| 86 | const variants = new Set<string>(); |
| 87 | const t = term.toLowerCase(); |
| 88 | |
| 89 | // -ing: caching→cach/cache, handling→handl/handle, running→run |
| 90 | if (t.endsWith('ing') && t.length > 5) { |
| 91 | const base = t.slice(0, -3); |
| 92 | variants.add(base); |
| 93 | variants.add(base + 'e'); |
| 94 | if (base.length >= 2 && base[base.length - 1] === base[base.length - 2]) { |
| 95 | variants.add(base.slice(0, -1)); |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | // -tion/-sion: eviction→evict, expression→express |
| 100 | if ((t.endsWith('tion') || t.endsWith('sion')) && t.length > 5) { |
| 101 | variants.add(t.slice(0, -3)); |
| 102 | } |
| 103 | |
| 104 | // -ment: management→manage |
| 105 | if (t.endsWith('ment') && t.length > 6) { |
| 106 | variants.add(t.slice(0, -4)); |
| 107 | } |
| 108 | |
| 109 | // -ies: entries→entry |
| 110 | if (t.endsWith('ies') && t.length > 4) { |
| 111 | variants.add(t.slice(0, -3) + 'y'); |
| 112 | } |
| 113 | // -es: processes→process, classes→class |
| 114 | else if (t.endsWith('es') && t.length > 4) { |
| 115 | variants.add(t.slice(0, -2)); |
| 116 | } |
| 117 | // -s: errors→error (skip -ss endings like "class") |
| 118 | else if (t.endsWith('s') && !t.endsWith('ss') && t.length > 4) { |
| 119 | variants.add(t.slice(0, -1)); |
| 120 | } |
| 121 | |
| 122 | // -ed: handled→handle, propagated→propagate, carried→carry |
| 123 | if (t.endsWith('ed') && !t.endsWith('eed') && t.length > 4) { |
| 124 | variants.add(t.slice(0, -1)); |
| 125 | variants.add(t.slice(0, -2)); |
| 126 | if (t.endsWith('ied') && t.length > 5) { |
| 127 | variants.add(t.slice(0, -3) + 'y'); |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | // -er: builder→build/builde, handler→handl/handle, getter→get |
| 132 | if (t.endsWith('er') && t.length > 4) { |
| 133 | const base = t.slice(0, -2); |
| 134 | variants.add(base); |
| 135 | variants.add(base + 'e'); |
| 136 | if (base.length >= 2 && base[base.length - 1] === base[base.length - 2]) { |
| 137 | variants.add(base.slice(0, -1)); |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | return [...variants].filter(v => v.length >= 3 && v !== t); |
| 142 | } |
no outgoing calls
no test coverage detected