/**
* 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