MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / findMatch

Function findMatch

src/tools/filesystem/fuzzy-match.ts:101–178  ·  view source on GitHub ↗
(
  content: string,
  search: string,
  opts: { fuzzyThreshold?: number; fuzzyMargin?: number; allowFuzzy?: boolean } = {},
)

Source from the content-addressed store, hash-verified

99 * Returns null if no confident match. The threshold/margin guard fuzzy tier.
100 */
101export function findMatch(
102 content: string,
103 search: string,
104 opts: { fuzzyThreshold?: number; fuzzyMargin?: number; allowFuzzy?: boolean } = {},
105): MatchResult | null {
106 const fuzzyThreshold = opts.fuzzyThreshold ?? 0.85;
107 const fuzzyMargin = opts.fuzzyMargin ?? 0.08;
108 const allowFuzzy = opts.allowFuzzy ?? true;
109
110 // ── Tier 0: exact ──
111 {
112 const first = content.indexOf(search);
113 if (first !== -1) {
114 const occurrences = content.split(search).length - 1;
115 return { start: first, end: first + search.length, matched: search, tier: 'exact', occurrences };
116 }
117 }
118
119 const contentLines = content.split('\n');
120 const searchLines = search.split('\n');
121 // Drop a trailing empty line from a search that ended in \n.
122 if (searchLines.length > 1 && searchLines[searchLines.length - 1] === '') searchLines.pop();
123 const nSearch = searchLines.length;
124 const lineStarts = computeLineStarts(content);
125
126 // ── Tier 1: line-trimmed exact ──
127 {
128 const normSearch = searchLines.map(normLine);
129 const matches: number[] = [];
130 for (let i = 0; i + nSearch <= contentLines.length; i++) {
131 let ok = true;
132 for (let j = 0; j < nSearch; j++) {
133 if (normLine(contentLines[i + j]!) !== normSearch[j]) { ok = false; break; }
134 }
135 if (ok) matches.push(i);
136 }
137 if (matches.length >= 1) {
138 const i = matches[0]!;
139 const { start, end } = lineRangeToOffsets(lineStarts, content, i, i + nSearch);
140 return {
141 start, end,
142 matched: content.slice(start, end),
143 tier: 'whitespace',
144 occurrences: matches.length,
145 };
146 }
147 }
148
149 // ── Tier 2: fuzzy anchor (only when the block is substantial) ──
150 const nonBlank = searchLines.filter(l => normLine(l).length > 0).length;
151 if (!allowFuzzy || nonBlank < 2) return null;
152
153 let best = { score: -1, index: -1 };
154 let second = { score: -1, index: -1 };
155 for (let i = 0; i + nSearch <= contentLines.length; i++) {
156 const window = contentLines.slice(i, i + nSearch);
157 const score = blockSim(window, searchLines);
158 if (score > best.score) {

Callers 2

executeMethod · 0.85

Calls 5

computeLineStartsFunction · 0.85
normLineFunction · 0.85
lineRangeToOffsetsFunction · 0.85
blockSimFunction · 0.85
pushMethod · 0.45

Tested by

no test coverage detected