/**
 * `naming-convention-fks` adapter — convention-FK relationship inference.
 *
 * Some codebases carry no explicit FK metadata: PowerSync (`column.text`
 * without `.references()`), hand-rolled Drizzle without relations, plain
 * SQL migrations without REFERENCES clauses. The relationship lives in the
 * column NAME (`club_id`, `userId`) by convention only. None of the
 * structural adapters (typescript-prisma / typescript-decorators /
 * typescript-interfaces / express-routes / react-views) catches this
 * pattern — typescript-interfaces sees `club_id: string` as a plain string
 * field, not a relationship.
 *
 * This adapter is a POST-EXTRACTION inference pass. It runs after all
 * structural adapters have populated `facts.entities[].attributes[]` and
 * walks those attributes for the `*_id` / `*Id` pattern, resolving the
 * prefix against the entity name set (singular OR plural form). When a
 * match resolves cleanly to a known entity, it emits a belongsTo
 * relationship from the owning entity to the target plus a reverse hasMany.
 *
 * Surfaced as a gap by the scoremyclays full-pipeline run 2026-05-12: 10
 * entities extracted, 0 relationships, because Supabase + PowerSync uses
 * convention FKs throughout (`club_id: column.text`).
 *
 * Cut 1 patterns:
 *   - `<entity>_id` (snake_case) or `<entity>Id` (camelCase), where the
 *     prefix maps to a known entity name (case-insensitive, singular OR
 *     plural via a small english heuristic).
 *
 * Out of scope (deferred to follow-up):
 *   - `created_by` / `assigned_to` / `owner_id` — target entity not named
 *     in the column (needs a curated semantic map OR LLM inference).
 *   - Composite FKs — same shape produces independent belongsTos; downstream
 *     can combine if it cares.
 *
 * Cardinality: forward `belongsTo` for every matched `*_id`. The reverse
 * `hasMany` is emitted ONLY when this adapter discovered the forward edge
 * itself — i.e. when a prior adapter hadn't already declared that
 * belongsTo. Rationale: rich-metadata codebases (TypeORM with explicit
 * @ManyToOne) decline to declare the inverse @OneToMany when they don't
 * navigate that way, and we shouldn't second-guess that omission. For
 * convention-only codebases (PowerSync) where no prior adapter saw the
 * relationship, BOTH directions are emitted so downstream gets a complete
 * cardinality view.
 *
 * Self-references (`parent_id` on Category → Category) emit only the
 * belongsTo regardless — `Category hasMany Category` is legal but rarely
 * the intended shape.
 *
 * Dedup: skip a candidate when the same `from|to|type` already exists in
 * the input relationships list (a higher-fidelity adapter wins).
 */
export interface NamingConventionFkInputEntity {
    name: string;
    attributes?: Array<{
        name: string;
        isPrimary?: boolean;
    }>;
}
export interface NamingConventionFkInputRelationship {
    from: string;
    to: string;
    type: 'belongsTo' | 'hasMany' | 'hasOne' | 'manyToMany';
}
export interface NamingConventionFkInferred {
    from: string;
    to: string;
    type: 'belongsTo' | 'hasMany';
    /** Source attribute that triggered the inference. Kept for downstream
     *  attribution + tests; the orchestrator drops this before merging into
     *  facts.relationships (which has no `fieldName` field on its canonical
     *  shape). */
    fieldName: string;
}
export interface NamingConventionFkFacts {
    relationships: NamingConventionFkInferred[];
    /** How many attributes matched the `*_id` / `*Id` pattern. */
    matchedAttributes: number;
    /** Matches that were skipped because the attribute is the entity's PK. */
    ignoredPrimaryKeys: number;
    /** Matches that resolved to no entity name. */
    unresolvedTargets: number;
}
export interface NamingConventionFkOptions {
    /** Override pluralization. Default: simple english heuristic. */
    pluralize?: (singular: string) => string;
    /** Override singularization. Default: simple english heuristic. */
    singularize?: (plural: string) => string;
}
export declare function inferNamingConventionFks(entities: NamingConventionFkInputEntity[], existingRelationships: NamingConventionFkInputRelationship[], options?: NamingConventionFkOptions): NamingConventionFkFacts;
//# sourceMappingURL=naming-convention-fks.d.ts.map