Files
gites/src/lib/filter.ts
T
szaman e4e597dc5c
ci / check (push) Successful in 3m3s
release / release (push) Successful in 11m34s
Eye on the Tags header hides all tags, also tags added later
2026-10-15 13:55:08 +02:00

67 lines
2.4 KiB
TypeScript

import type { Commit, FilterState, Ref, RefKind } from "./types";
export function refKind(name: string): RefKind {
if (name.startsWith("refs/remotes/")) return "remote";
if (name.startsWith("refs/tags/")) return "tag";
return "local";
}
export function shortName(name: string): string {
return name.replace(/^refs\/(heads|remotes|tags)\//, "");
}
/** `*` matches any run of characters (including `/`), `?` matches one character. */
export function globMatch(pattern: string, text: string): boolean {
const re = pattern
.split("")
.map((ch) => (ch === "*" ? ".*" : ch === "?" ? "." : ch.replace(/[.+^${}()|[\]\\]/g, "\\$&")))
.join("");
return new RegExp(`^${re}$`).test(text);
}
export function isRefVisible(name: string, state: FilterState): boolean {
if (state.hidden.includes(name)) return false;
if (state.hideTags && name.startsWith("refs/tags/")) return false;
const short = shortName(name);
const only = state.rules.filter((r) => r.mode === "only");
if (only.length > 0 && !only.some((r) => globMatch(r.pattern, short))) return false;
return !state.rules.some((r) => r.mode === "hide" && globMatch(r.pattern, short));
}
/** Commits reachable from `starts`, in the original order. */
export function reachable(commits: Commit[], starts: Iterable<string>): Commit[] {
const byHash = new Map(commits.map((c) => [c.hash, c]));
const seen = new Set<string>();
const stack = [...starts];
while (stack.length > 0) {
const h = stack.pop()!;
if (seen.has(h)) continue;
const c = byHash.get(h);
if (!c) continue;
seen.add(h);
stack.push(...c.parents);
}
return commits.filter((c) => seen.has(c.hash));
}
const kindOrder: Record<RefKind, number> = { local: 0, remote: 1, tag: 2 };
/** For each commit, the ref whose first-parent line it lies on. */
export function lineOwners(commits: Commit[], refs: Ref[], headRef: string | null): Map<string, string> {
const byHash = new Map(commits.map((c) => [c.hash, c]));
const ordered = [...refs].sort(
(a, b) =>
Number(b.name === headRef) - Number(a.name === headRef) ||
kindOrder[refKind(a.name)] - kindOrder[refKind(b.name)],
);
const owners = new Map<string, string>();
for (const ref of ordered) {
let c = byHash.get(ref.target);
while (c && !owners.has(c.hash)) {
owners.set(c.hash, ref.name);
c = byHash.get(c.parents[0]);
}
}
return owners;
}