import fs from 'fs';
import path from 'path';
import { ApiRoute } from '../crawler/api';
import { suggestHookImplementation, loadMCPConfig } from '../ai/mcpAgent';
export interface GeneratorOptions {
outputDir: string;
useSWRInfinite?: boolean;
graphqlInfiniteQueries?: string[];
aiAgent?: 'none' | 'copilot' | 'openai' | 'custom';
dryRun?: boolean;
}
export async function generateHooks(apiRoutes: ApiRoute[], options: GeneratorOptions) {
const {
outputDir,
useSWRInfinite = false,
graphqlInfiniteQueries = [],
aiAgent = 'none',
dryRun = false,
} = options;
if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true });
const hooks: string[] = [];
const imports: Record<string, string[]> = {};
for (const route of apiRoutes) {
const baseName = path.basename(route.path, '.ts').replace(/\W+/g, '');
const safeName = baseName.charAt(0).toUpperCase() + baseName.slice(1);
if (route.kind === 'api-client') {
if (!imports[route.path]) imports[route.path] = [];
imports[route.path].push(...route.methods);
}
for (const method of route.methods) {
const hookName = `use${safeName}${method}`;
const serverFnName = `fetch${safeName}${method}`;
const env = route.environment || 'client';
// -----------------
// Server-only function
// -----------------
if (env === 'server' || env === 'universal') {
hooks.push(`
export async function ${serverFnName}() {
const { ${method} } = await import("${route.path.replace(/\.ts$/, '')}");
return ${method}();
}`);
}
// -----------------
// Client-side hook
// -----------------
if (env === 'client' || env === 'universal') {
if (route.kind === 'next-route' || route.kind === 'api-client') {
if (useSWRInfinite) {
hooks.push(`
export function ${hookName}(getKey: (pageIndex: number, previousPageData: any) => string | null) {
return useSWRInfinite<any>(getKey, async (url: string) => {
const res = await fetch(url);
if (!res.ok) throw new Error("Request failed");
return res.json();
});
}`);
} else {
hooks.push(`
export function ${hookName}(key?: string) {
return useSWR<any>(key || "${route.path}", async (url: string) => {
const res = await fetch(url);
if (!res.ok) throw new Error("Request failed");
return res.json();
});
}`);
}
}
// GraphQL hooks can be added here similarly
}
// -----------------
// AI Suggestion Integration
// -----------------
if (aiAgent !== 'none' && !dryRun) {
const aiSuggestion = await suggestHookImplementation(hookName, route, aiAgent);
hooks.push(`\n// 🤖 AI Suggestion for ${hookName}\n${aiSuggestion}\n`);
}
}
}
const importLines = Object.entries(imports).map(([filePath, funcs]) => {
const relPath =
'./' + path.relative(outputDir, filePath).replace(/\\/g, '/').replace(/\.ts$/, '');
return `import { ${Array.from(new Set(funcs)).join(', ')} } from "${relPath}";`;
});
const fileContent = `
// AUTO-GENERATED FILE - DO NOT EDIT
import useSWR${
useSWRInfinite || apiRoutes.some((r) => r.kind.includes('graphql'))
? ', { useSWRInfinite }'
: ''
} from "swr";
${importLines.join('\n')}
${hooks.join('\n')}
`;
fs.writeFileSync(path.join(outputDir, 'hooks.ts'), fileContent, 'utf-8');
console.log(`âś… Hooks generated at ${path.join(outputDir, 'hooks.ts')}`);
}