/** Region markers SpecVerse-realized backends emit in behavior method bodies. */
const REGION_MARKERS = {
    preconditions: /===\s*PRECONDITIONS\s*===/,
    execute: /===\s*EXECUTE\s*===/,
    postconditions: /===\s*POSTCONDITIONS\s*===/,
    events: /===\s*EVENTS\s*===/,
};
/** Slice a method body into the canonical PRECONDITIONS/EXECUTE/POSTCONDITIONS/EVENTS regions. */
export function sliceBody(body) {
    // Detect each marker's position in the body
    const positions = [];
    for (const [name, regex] of Object.entries(REGION_MARKERS)) {
        const match = body.match(regex);
        if (match && match.index !== undefined) {
            positions.push({ name: name, pos: match.index });
        }
    }
    if (positions.length === 0)
        return undefined;
    positions.sort((a, b) => a.pos - b.pos);
    const out = {};
    for (let i = 0; i < positions.length; i++) {
        const { name, pos } = positions[i];
        const next = i + 1 < positions.length ? positions[i + 1].pos : body.length;
        out[name] = body.slice(pos, next).trim();
    }
    return out;
}
/** Extract event names emitted from a TS/JS method body. */
export function extractEmits(body) {
    const out = new Set();
    // Common emission patterns:
    //   eventBus.emit('Foo', ...)             eventBus.publish('Foo', ...)
    //   emit('Foo', ...)                      this.dispatchEvent('Foo', ...)
    //   subject.next(new FooEvent())          this.bus.publish('Foo', ...)
    //   pubsub.publish('Foo', ...)            this.events.emit('Foo', ...)
    const stringEmitRegex = /(?:emit|publish|dispatchEvent|next)\s*\(\s*['"`]([^'"`]+)['"`]/g;
    for (const m of body.matchAll(stringEmitRegex)) {
        out.add(m[1]);
    }
    // For "subject.next(new FooEvent())" type patterns, capture the constructor name
    const constructorEmitRegex = /\.next\s*\(\s*new\s+(\w+Event)\s*\(/g;
    for (const m of body.matchAll(constructorEmitRegex)) {
        out.add(m[1]);
    }
    return [...out];
}
/** Extract Prisma-style DB writes from a TS/JS method body. */
export function extractDbWrites(body) {
    const out = [];
    // Prisma: prisma.modelName.create(...)/.update(...)/.delete(...)/.upsert(...)
    // Capture entity name (camelCase) and op
    const prismaRegex = /\bprisma\.(\w+)\.(create|update|delete|upsert|createMany|updateMany|deleteMany)\s*\(/g;
    for (const m of body.matchAll(prismaRegex)) {
        const entity = m[1].charAt(0).toUpperCase() + m[1].slice(1); // pollOption → PollOption
        const opRaw = m[2];
        const op = opRaw.startsWith('create')
            ? 'create'
            : opRaw.startsWith('update')
                ? 'update'
                : opRaw.startsWith('delete')
                    ? 'delete'
                    : opRaw === 'upsert'
                        ? 'upsert'
                        : 'unknown';
        out.push({ entity, op });
    }
    // TypeORM: repository.save() / .update() / .remove()
    const typeormRegex = /\b(\w*[Rr]epository)\.(save|update|remove|delete|insert|upsert)\s*\(/g;
    for (const m of body.matchAll(typeormRegex)) {
        const repoName = m[1];
        const entity = repoName.replace(/Repository$/i, '');
        const opRaw = m[2];
        const op = opRaw === 'save' || opRaw === 'insert'
            ? 'create'
            : opRaw === 'update'
                ? 'update'
                : opRaw === 'remove' || opRaw === 'delete'
                    ? 'delete'
                    : opRaw === 'upsert'
                        ? 'upsert'
                        : 'unknown';
        if (entity)
            out.push({ entity, op });
    }
    return out;
}
/** Extract external system calls from a TS/JS method body. */
export function extractExternalCalls(body) {
    const out = [];
    // HTTP: fetch / axios.X / http.request / got / undici
    if (/\bfetch\s*\(/.test(body) || /\baxios\.\w+\s*\(/.test(body) ||
        /\bhttp[s]?\.(request|get|post)\s*\(/.test(body) ||
        /\bgot\.\w+\s*\(/.test(body)) {
        out.push({ kind: 'http' });
    }
    // Queue: kafka / rabbit / sqs
    if (/\bkafka\.\w+\s*\(/.test(body) || /\brabbit\w*\.\w+\s*\(/.test(body) ||
        /\bsqs\.\w+\s*\(/.test(body)) {
        out.push({ kind: 'queue' });
    }
    // Cache: redis / memcached / cache.X
    if (/\bredis\.\w+\s*\(/.test(body) || /\bmemcached\.\w+\s*\(/.test(body) ||
        /\bcache\.\w+\s*\(/.test(body)) {
        out.push({ kind: 'cache' });
    }
    return out;
}
/** Extract throw statements (the type of error being thrown). */
export function extractThrows(body) {
    const out = new Set();
    // throw new ErrorType(...) — captures the constructor name
    const throwNewRegex = /throw\s+new\s+(\w+)\s*\(/g;
    for (const m of body.matchAll(throwNewRegex)) {
        out.add(m[1]);
    }
    return [...out];
}
/** Find async boundaries (await / Promise.all / Promise.race). */
export function extractAsyncBoundaries(body) {
    const out = [];
    const lines = body.split('\n');
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        if (/\bawait\b/.test(line)) {
            if (/Promise\.all\b/.test(line)) {
                out.push({ type: 'promise.all', line: i + 1 });
            }
            else if (/Promise\.race\b/.test(line)) {
                out.push({ type: 'promise.race', line: i + 1 });
            }
            else if (/Promise\.allSettled\b/.test(line)) {
                out.push({ type: 'promise.allSettled', line: i + 1 });
            }
            else {
                out.push({ type: 'await', line: i + 1 });
            }
        }
    }
    return out;
}
/** Count branch points — if / else if / switch case / catch / ternary. */
export function countBranchPoints(body) {
    let count = 0;
    // `if (...)`, but exclude `else if` (avoids double-counting; we count the if portion)
    count += (body.match(/\bif\s*\(/g) || []).length;
    count += (body.match(/\bcase\s+/g) || []).length;
    count += (body.match(/\bcatch\s*\(/g) || []).length;
    // Ternaries: `... ? ... : ...` — count each occurrence of `?...:` (rough proxy)
    count += (body.match(/\?\s*[^:?]+:/g) || []).length;
    return count;
}
/**
 * Heuristic: extract called functions from a method body via regex
 * (fallback when call graph isn't available — grep-only backend).
 * Returns deduplicated function names. Filters out language keywords.
 */
const KEYWORD_FILTER = new Set([
    'if', 'for', 'while', 'switch', 'catch', 'return', 'throw', 'new',
    'await', 'typeof', 'instanceof', 'function', 'async', 'yield',
    'console', 'JSON', 'Object', 'Array', 'String', 'Number', 'Boolean',
    'Math', 'Date', 'Promise', 'Error', 'Map', 'Set',
]);
export function extractCallNames(body) {
    const out = new Set();
    // Match `name(` or `obj.name(` — capture the identifier before `(`
    // For chained calls (obj.method()), this captures the last identifier
    const callRegex = /\b(\w+)\s*\(/g;
    for (const m of body.matchAll(callRegex)) {
        const name = m[1];
        if (KEYWORD_FILTER.has(name))
            continue;
        out.add(name);
    }
    return [...out];
}
//# sourceMappingURL=method-patterns.js.map