~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
108 lines · 4.5 KB Raw History
import type * as listRepos from '#lib/lexicons/dev/knotless/listRepos.ts';
import type * as searchCode from '#lib/lexicons/dev/knotless/searchCode.ts';
import type * as searchOwners from '#lib/lexicons/dev/knotless/searchOwners.ts';
import type { Answer } from '#lib/data.ts';
import type { PageLoad } from './$types';
import { xrpc } from '#lib/data.ts';

/** What a code search found, or why it found nothing. */
export type CodeFound =
	| { kind: 'found'; answer: Answer<typeof searchCode.main> }
	| { kind: 'off' }
	| { kind: 'bad'; message: string }
	| { kind: 'missing'; repo: string }
	| { kind: 'none' };

/** `repo:owner/name` in a query, which searches that repository's code alone. */
const REPO = /(?:^|\s)repo:(\S+?)\/(\S+)(?=\s|$)/;

/**
 * What the results page shows of `q`: its code, with `type=code`, else
 * the repositories that match it, or every one, newest first, those about
 * `topic` alone when one is named, and the owners whose handles hold it.
 * Code is searched in one repository when `q` names it as
 * `repo:owner/name`. None of either, without an index. Each kind is
 * counted, for a search, by asking for the other kind too.
 */
export const load: PageLoad = async (event) => {
	const q = (event.url.searchParams.get('q') ?? '').trim();
	const topic = (event.url.searchParams.get('topic') ?? '').trim() || undefined;
	const type = event.url.searchParams.get('type') === 'code' ? 'code' : 'repositories';
	// The page is cached as the repositories are.
	const quiet = { ...event, setHeaders: () => {} };
	// Each kind's count beside it, for a search: the other kind asked too.
	// Repositories are asked for with the words alone, not a code search's `lang:`.
	const words = type === 'code' ? q.replace(/(^|\s)-?lang:("[^"]*"|\S+)/g, ' ').trim() : q;
	const listed = (e: typeof event) =>
		words || type === 'repositories'
			? xrpc<typeof listRepos.main>(e, 'dev.knotless.listRepos', { q: words, topic }, true)
			: null;
	if (type === 'code') {
		const cursor = event.url.searchParams.get('cursor') ?? undefined;
		const [found, repos] = await Promise.all([
			code(event, q, undefined, cursor),
			REPO.test(q) ? null : listed(quiet)
		]);
		const counts = {
			code: found.kind === 'found' ? found.answer.fileCount : undefined,
			...reposCounted(repos)
		};
		return { query: q, topic, type, code: found, counts, repos: [], owners: [], indexed: true };
	}
	const [found, owners, files] = await Promise.all([
		listed(event),
		q ? xrpc<typeof searchOwners.main>(quiet, 'dev.knotless.searchOwners', { q }, true) : null,
		q && !topic ? code(quiet, q, 1) : null
	]);
	// Each with its owner, as the list shows it; whose fork it is, it does not.
	const repos =
		found?.repos.flatMap(({ forkOf: _, owner, ...r }) => (owner ? [{ ...r, owner }] : [])) ?? [];
	const none: CodeFound = { kind: 'none' };
	const counts = {
		code: files?.kind === 'found' ? files.answer.fileCount : undefined,
		...(q ? reposCounted(found) : {})
	};
	return {
		query: q,
		topic,
		type,
		code: none,
		counts,
		repos,
		owners: owners?.owners ?? [],
		indexed: found !== null
	};
};

/** How many repositories a page of them counts, `more` when there are others after it. */
function reposCounted(found: Answer<typeof listRepos.main> | null) {
	return found ? { repos: found.repos.length, more: found.cursor !== undefined } : {};
}

/**
 * The code `q` finds, after the files `cursor` says the pages before
 * held: asked here rather than by `xrpc`, as a query Zoekt
 * cannot read, or a server that searches no code, is said on the page
 * rather than failing it.
 */
async function code(
	event: Parameters<PageLoad>[0],
	q: string,
	limit?: number,
	cursor?: string
): Promise<CodeFound> {
	const named = REPO.exec(q);
	const rest = named ? q.replace(named[0], ' ').trim() : q;
	if (!rest) return { kind: 'none' };
	const params = new URLSearchParams({ q: rest });
	if (named) params.set('repo', `at://${named[1]}/dev.knotless.repo/${named[2]}`);
	if (limit) params.set('limit', String(limit));
	if (cursor) params.set('cursor', cursor);
	const res = await event.fetch(`/xrpc/dev.knotless.searchCode?${params}`, { cache: 'no-cache' });
	if (res.ok) return { kind: 'found', answer: await res.json() };
	if (res.status === 501) return { kind: 'off' };
	// The repository `repo:` names is no one's.
	if (res.status === 404 && named) return { kind: 'missing', repo: `${named[1]}/${named[2]}` };
	const failure: { message?: string } | null = await res.json().catch(() => null);
	return { kind: 'bad', message: failure?.message ?? res.statusText };
}