/** * 0.19.0-alpha.8 — recon reuse-scan: deterministic near-duplicate * detection for components AND API routes / utility modules. Pure * functions for testing; cli wiring in `recon/index.ts`'s * --reuse-scan flag. * * Why this exists: when driver creates `NewItemCard` that's near- * identical to existing `RewoCard` — OR when two API routes both * do auth → query → NextResponse.json with similar shapes — * navigator can't catch it (its prompt is calibrated for diff- * level critique, not codebase-scale similarity). A static AST-ish * hash + Jaccard similarity catches it cheaply + deterministically. * False positives are acceptable because the refactor command's * ranking + the PM's eyeball filter the noise. * * Approach: regex-extract a "structural signature" (JSX tags, * destructured params, calls, exports, imports). Auto-categorize * by JSX presence: component-vs-component uses jsx-heavy weighting, * api-vs-api uses calls-heavy, cross-category pairs short-circuit * to 0 (we don't compare a component against a route handler). */ export interface ScanSignature { /** Repo-relative path. */ path: string; /** Identifiers exported from the file (default + named). */ exports: string[]; /** Identifiers imported (across all import statements). */ imports: string[]; /** Distinct JSX element types (`
`, ``). Empty for API/utility files. */ jsxTags: string[]; /** Params destructured from the function arg (`{ a, b }: Props`, * or `({ id }: { id: string })`). */ propsUsed: string[]; /** Function calls (e.g. `useState`, `supabase.from`, `NextResponse.json`, * `fetch`). Broader than just React hooks — captures the structural * fingerprint of API + utility modules too. */ callsUsed: string[]; } /** * Extract a structural signature from a TS/TSX file's source. * Pure: takes (path, source); returns a normalized signature. * * Works for components (JSX tags will be populated), API route * handlers (callsUsed captures supabase/auth/NextResponse), and * utility modules (callsUsed + exports). Strings + comments are * NOT stripped — false positives are rare for the categories we * capture. */ export declare function extractStructuralSignature(path: string, source: string): ScanSignature; /** * Jaccard similarity of two string sets. Pure. * |a ∩ b| / |a ∪ b| * Returns 1 if both sets empty (degenerate equal-empty case); * 0 if one is empty + the other isn't. */ export declare function jaccard(a: string[], b: string[]): number; /** * 0.19.0-α.10 (#85) — detect "this file is auto-generated, exclude * from refactor-candidate scanning." Pure: takes file content, returns * true if any of these markers appears in the first 400 characters: * * `@slowcook-template` — explicit "slowcook generated me" marker * `@slowcook-stub` — placeholder waiting for brew to overwrite * `@generated` — common convention (Facebook/Meta tooling) * `AUTO-GENERATED` — case-insensitive plain English * `auto-generated by` — common phrasing in tool output * `Do not edit by hand` — common phrasing in templated files * * 400 chars is enough to capture a typical file header without scanning * the whole body. Markers later in the file are deliberately ignored * (e.g., a comment in the middle of a file mentioning "auto-generated" * shouldn't kill the file's signal). */ export declare function isAutoTemplateFile(content: string): boolean; /** * 0.19.0-α.10 (#85) — match a single file path against a glob-ish * exclusion pattern. Same shape as the refactor command's matchesScope * (kept inline rather than cross-package-imported to avoid coupling * recon to the refactor module). * * Supported: * - exact match: "src/foo.ts" * - directory prefix: "src/lib/entities/" (matches anything under) * - star at end: "src/lib/data/*" (one segment after) * - double-star: "src/lib/entities/**" (any depth) * - filename glob: "*.mock.ts" (matches any path ending with) */ export declare function matchesExcludePattern(filePath: string, pattern: string): boolean; /** * Compute similarity between two structural signatures. Auto- * categorizes by JSX presence: * * component-vs-component (both have jsxTags): * 0.50 jsx + 0.30 props + 0.20 calls * * api/utility-vs-api/utility (both jsxTags empty): * 0.60 calls + 0.30 props + 0.10 imports * * cross-category (one has jsx, other doesn't): * return 0 — comparing a component to a route handler is * never a useful "duplicate" finding. * * Returns a number in [0, 1]. Default duplicate threshold: 0.7. */ export declare function signatureSimilarity(a: ScanSignature, b: ScanSignature): number; export interface DuplicatePair { a: string; b: string; similarity: number; /** Whether the pair is component-vs-component or api-vs-api. */ category: "component" | "api-or-util"; /** Per-axis breakdown for the operator. */ axes: { jsx: number; props: number; calls: number; imports: number; }; } /** * Scan a list of structural signatures + return all pairs whose * similarity is >= threshold. Output is sorted by similarity * descending. Pure: caller owns IO (reading files into the * signatures array). */ export declare function scanForDuplicates(signatures: ScanSignature[], threshold?: number): DuplicatePair[]; /** * Convert a duplicate-pair finding into a refactor proposal that * the `slowcook refactor` command can rank. Pure synthesis — no IO. * * The proposal has: * - id: deterministic from the pair (so re-running doesn't dup) * - title: "consolidate + (NN% similar)" with the category * - filesAffected: both paths * - estimatedLocDelta: caller doesn't know, conservative 0 * (the proposal tells you to merge; the actual diff happens * when someone DOES the work) * - estimatedValueScore: scaled from similarity * (similarity 0.7 → 5; 0.85 → 7; 0.95 → 9) */ export declare function pairToRefactorProposal(pair: DuplicatePair): { id: string; title: string; rationale: string; filesAffected: string[]; estimatedLocDelta: number; estimatedValueScore: number; evidence: Record; }; //# sourceMappingURL=reuse.d.ts.map