File size: 2,818 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
 * Incremental re-sync of idea files: append new comments only,
 * update frontmatter snapshot.
 */
import { parseFrontmatter, serializeFrontmatter, stripFrontmatter } from "./frontmatter.mjs";
import { isBot } from "./classify.mjs";

function countThumbs(reactionGroups) {
  if (!Array.isArray(reactionGroups)) return 0;
  const g = reactionGroups.find((rg) => rg.content === "THUMBS_UP");
  return g?.users?.totalCount ?? 0;
}

function uniqueCommenters(comments, authorLogin) {
  const seen = new Set();
  for (const c of comments ?? []) {
    const u = c.author;
    if (!u || !u.login) continue;
    if (u.login === authorLogin) continue;
    if (isBot(u)) continue;
    seen.add(u.login);
  }
  return seen.size;
}

function renderComments(comments) {
  return comments
    .map(
      (c) =>
        `- **@${c.author?.login ?? "unknown"}** (${c.createdAt}):\n  > ${(c.body ?? "").split("\n").join("\n  > ")}`
    )
    .join("\n");
}

function appendComments(body, newComments) {
  const heading = "## 💬 Community Discussion";
  let idx = body.indexOf(heading);
  if (idx < 0) idx = body.indexOf("## Community Discussion");
  if (idx < 0) {
    return body + `\n\n${heading}\n\n` + renderComments(newComments);
  }
  const after = body.slice(idx);
  const nextHeaderMatch = after.slice(heading.length).match(/^##\s+/m);
  const insertAt = nextHeaderMatch ? idx + heading.length + nextHeaderMatch.index : body.length;
  const insertBlock = "\n\n" + renderComments(newComments) + "\n";
  return body.slice(0, insertAt) + insertBlock + body.slice(insertAt);
}

export function resyncIdeaFile(text, issue, now = new Date(), opts = {}) {
  const meta = parseFrontmatter(text);
  if (!meta) return { changed: false, text };

  const lastSyncedId = Number(meta.last_synced_comment_id ?? 0);
  const allComments = issue.comments ?? [];
  const newComments = allComments.filter((c) => Number(c.databaseId) > lastSyncedId);

  if (newComments.length === 0) {
    return { changed: false, text };
  }

  const body = stripFrontmatter(text);
  const newBody = appendComments(body, newComments);

  const newMeta = {
    ...meta,
    last_synced_at: now.toISOString(),
    last_synced_comment_id: Math.max(...newComments.map((c) => Number(c.databaseId))),
    snapshot: {
      ...(meta.snapshot ?? {}),
      thumbs: countThumbs(issue.reactionGroups),
      commenters: uniqueCommenters(allComments, issue.author?.login),
      labels: (issue.labels ?? []).map((l) => l.name).filter(Boolean),
      state: String(issue.state ?? "open").toLowerCase(),
    },
  };

  const out = serializeFrontmatter(newMeta, newBody);

  const needsReclassification = !!(
    opts.inNeedDetails && newComments.some((c) => c.author?.login === issue.author?.login)
  );

  return { changed: true, text: out, needsReclassification };
}