MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / extractMapper

Method extractMapper

src/extraction/mybatis-extractor.ts:170–255  ·  view source on GitHub ↗
(
    fileNodeId: string,
    namespace: string,
    dialect: 'mybatis' | 'ibatis',
    bodyStart: number,
    bodyEnd: number
  )

Source from the content-addressed store, hash-verified

168 }
169
170 private extractMapper(
171 fileNodeId: string,
172 namespace: string,
173 dialect: 'mybatis' | 'ibatis',
174 bodyStart: number,
175 bodyEnd: number
176 ): void {
177 const body = this.source.slice(bodyStart, bodyEnd);
178 // Match each top-level statement-shaped element. The body may have nested
179 // tags (`<if>`, `<foreach>`, `<include>`), so we scan with a regex that
180 // pairs an opening tag to its matching close — the simple form below works
181 // because MyBatis/iBatis statement elements are not themselves nested.
182 // iBatis 2 adds the generic `<statement>` and `<procedure>` on top of the
183 // MyBatis 3 verbs; gating by dialect keeps MyBatis extraction unchanged.
184 const verbs =
185 dialect === 'ibatis'
186 ? 'select|insert|update|delete|sql|statement|procedure'
187 : 'select|insert|update|delete|sql';
188 const stmtRegex = new RegExp(`<(${verbs})\\b([^>]*)>([\\s\\S]*?)</\\1>`, 'g');
189 let m: RegExpExecArray | null;
190 while ((m = stmtRegex.exec(body)) !== null) {
191 const elemType = m[1]!;
192 const attrs = m[2] ?? '';
193 const elemBody = m[3] ?? '';
194 // Accept either quote style (`(["'])…\1`). The identifier-shaped MyBatis
195 // attributes matched here and below (namespace/id/refid/resultType/
196 // parameterType) are Java FQNs, method names, or type aliases and never
197 // contain a quote character, so excluding both quotes from the value is safe.
198 const idMatch = /\bid\s*=\s*(["'])([^"']+)\1/.exec(attrs);
199 if (!idMatch) continue;
200 const id = idMatch[2]!;
201 const absoluteIndex = bodyStart + m.index;
202 const startLine = this.getLineNumber(absoluteIndex);
203 const endLine = this.getLineNumber(absoluteIndex + m[0].length);
204 const { qualifiedName: qualified, name } = this.qualifyStatement(namespace, id);
205 const isSqlFragment = elemType === 'sql';
206 // The id-hash folds in the statement's byte offset (unique per statement
207 // in the file), not just the start line: two statements sharing a
208 // qualifiedName AND a start line — e.g. a vendor-split `databaseId` pair
209 // (`<select id="x" databaseId="oracle">…</select><select id="x"
210 // databaseId="mysql">…`) written on one line — would otherwise hash to
211 // the same node id, and `INSERT OR REPLACE INTO nodes` (id is the PRIMARY
212 // KEY) would silently drop one. qualifiedName and startLine are stored
213 // unchanged, so the Java↔XML suffix-match bridge is untouched.
214 const nodeId = generateNodeId(this.filePath, 'method', qualified, absoluteIndex);
215 const node: Node = {
216 id: nodeId,
217 kind: 'method',
218 name,
219 qualifiedName: qualified,
220 filePath: this.filePath,
221 language: 'xml',
222 signature: this.buildSignature(elemType, attrs, isSqlFragment),
223 startLine,
224 endLine,
225 startColumn: 0,
226 endColumn: 0,
227 docstring: this.previewSql(elemBody),

Callers 1

extractMethod · 0.95

Calls 6

getLineNumberMethod · 0.95
qualifyStatementMethod · 0.95
buildSignatureMethod · 0.95
previewSqlMethod · 0.95
generateNodeIdFunction · 0.90
execMethod · 0.65

Tested by

no test coverage detected