namespace Repoverse.Core.Model;
/// Stable internal identity for a repository: lower-cased "owner/name".
public readonly record struct RepoId(string Owner, string Name)
{
public string Key => $"{Owner.ToLowerInvariant()}/{Name.ToLowerInvariant()}";
public override string ToString() => Key;
public static RepoId Parse(string fullName)
{
var slash = fullName.IndexOf('/');
if (slash <= 0 || slash == fullName.Length - 1)
throw new FormatException($"Expected 'owner/name', got '{fullName}'.");
return new RepoId(fullName[..slash], fullName[(slash + 1)..]);
}
}
public enum TreeEntryKind { File, Directory }
public sealed record TreeEntry(string Path, TreeEntryKind Kind, long SizeBytes);
public sealed record Release(string Tag, DateTimeOffset PublishedAt, bool Prerelease);
///
/// GitHub-sourced facts about a repository. Nothing in here is inferred by Repoverse;
/// derived values live in with provenance.
///
public sealed record CanonicalRepository
{
public required RepoId Id { get; init; }
public string? Description { get; init; }
public string? PrimaryLanguage { get; init; }
/// Bytes of code per language, as reported by GitHub's languages endpoint.
public IReadOnlyDictionary Languages { get; init; } = new Dictionary();
public IReadOnlyList Topics { get; init; } = [];
public long SizeKb { get; init; }
public bool Archived { get; init; }
public bool Fork { get; init; }
public string DefaultBranch { get; init; } = "main";
public DateTimeOffset CreatedAt { get; init; }
public DateTimeOffset PushedAt { get; init; }
public string? License { get; init; }
public int OpenIssues { get; init; }
public int OpenPullRequests { get; init; }
public int Contributors { get; init; }
public int CommitsLast90Days { get; init; }
public IReadOnlyList Releases { get; init; } = [];
public IReadOnlyList Tree { get; init; } = [];
/// Other repos in the world this one depends on (from manifests / submodules).
public IReadOnlyList DependsOn { get; init; } = [];
/// Opaque version marker of the snapshot this record came from (e.g. pushed_at + ETag).
public string SnapshotId { get; init; } = "";
}