1import type { PullRequestReviewCommentDraft } from "@t3tools/contracts";
2import * as Schema from "effect/Schema";
3import { PullRequestReviewCommentDraft as CommentSchema } from "@t3tools/contracts";
4import type { PullRequestParams } from "./usePullRequestDiff";
5
6export type PendingReviewComment = PullRequestReviewCommentDraft & {
7 readonly id: string;
8 readonly headSha: string;
9 readonly code: string;
10};
11export type ReviewDraft = {
12 readonly summary: string;
13 readonly comment: string;
14 readonly comments: readonly PendingReviewComment[];
15};
16export const EMPTY_REVIEW_DRAFT: ReviewDraft = { summary: "", comment: "", comments: [] };
17export function pullRequestReviewKey(params: PullRequestParams) {
18 return JSON.stringify([
19 params.environmentId,
20 params.projectId,
21 params.host ?? "",
22 params.repository,
23 params.number,
24 ]);
25}
26export const ReviewDraftDocument = Schema.Struct({
27 version: Schema.Literal(1),
28 drafts: Schema.Record(
29 Schema.String,
30 Schema.Struct({
31 summary: Schema.String,
32 comment: Schema.String,
33 comments: Schema.Array(
34 Schema.Struct({
35 ...CommentSchema.fields,
36 id: Schema.String,
37 headSha: Schema.String,
38 code: Schema.String,
39 }),
40 ),
41 }),
42 ),
43});
44/** A successful request only clears the exact snapshot it posted. */
45export function clearSubmittedReview(current: ReviewDraft, submitted: ReviewDraft): ReviewDraft {
46 return {
47 ...current,
48 summary: current.summary === submitted.summary ? "" : current.summary,
49 comments: current.comments.filter(
50 (comment) =>
51 !submitted.comments.some(
52 (saved) =>
53 saved.id === comment.id &&
54 saved.body === comment.body &&
55 saved.headSha === comment.headSha &&
56 saved.path === comment.path &&
57 saved.oldPath === comment.oldPath &&
58 saved.code === comment.code &&
59 samePosition(saved.position, comment.position),
60 ),
61 ),
62 };
63}
64
65function samePosition(
66 left: PendingReviewComment["position"],
67 right: PendingReviewComment["position"],
68) {
69 if (left.kind === "added" && right.kind === "added") return left.newLine === right.newLine;
70 if (left.kind === "deleted" && right.kind === "deleted") return left.oldLine === right.oldLine;
71 return (
72 left.kind === "context" &&
73 right.kind === "context" &&
74 left.oldLine === right.oldLine &&
75 left.newLine === right.newLine &&
76 left.side === right.side
77 );
78}