import type { IssueComment } from '../../lib/api/issues';
import type { SearchParamValue } from '../../lib/repo-utils';
export type IssueStateFilter = 'open' | 'closed';
export interface IssueFilter {
state: IssueStateFilter;
author?: string;
query?: string;
}
const searchParamString = (value: SearchParamValue): string => Array.isArray(value) ? value[0] ?? '' : value ?? '';
export const parseIssueFilter = (value: SearchParamValue): IssueFilter => {
const filter: IssueFilter = { state: 'open' };
const tokens = searchParamString(value).split(/\s+/).filter(Boolean);
const queryTokens: string[] = [];
for (const token of tokens) {
if (token === 'state:closed') {
filter.state = 'closed';
continue;
}
if (token === 'state:open') {
filter.state = 'open';
continue;
}
if (token.startsWith('author:')) {
const author = token.slice('author:'.length).trim();
if (author) {
filter.author = author;
}
continue;
}
queryTokens.push(token);
}
const query = queryTokens.join(' ').trim();
if (query) {
filter.query = query;
}
return filter;
};
export const buildIssueFilterQuery = (filter: IssueFilter): string =>
[
filter.query,
`state:${filter.state}`,
filter.author ? `author:${filter.author}` : undefined,
].filter(Boolean).join(' ');
export type IssueCommentThread = {
item: IssueComment;
replies: IssueComment[];
};
export const buildIssueCommentThreads = (comments: IssueComment[]): IssueCommentThread[] => {
const byUri = new Map(comments.map((comment) => [comment.uri, comment]));
const topLevel: IssueComment[] = [];
const repliesByRoot = new Map<string, IssueComment[]>();
const findRoot = (comment: IssueComment): IssueComment | null => {
let current = comment;
const visited = new Set<string>([comment.uri]);
while (current.value.replyTo) {
const parent = byUri.get(current.value.replyTo);
if (!parent || visited.has(parent.uri)) {
return current === comment ? null : current;
}
current = parent;
visited.add(current.uri);
}
return current;
};
for (const comment of comments) {
const root = findRoot(comment);
if (!root || root.uri === comment.uri) {
topLevel.push(comment);
continue;
}
repliesByRoot.set(root.uri, [...(repliesByRoot.get(root.uri) ?? []), comment]);
}
return topLevel.map((item) => ({
item,
replies: repliesByRoot.get(item.uri) ?? [],
}));
};