comment-note.ts 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import type { FileSelection } from "@/context/file"
  2. export type PromptComment = {
  3. path: string
  4. selection?: FileSelection
  5. comment: string
  6. preview?: string
  7. origin?: "review" | "file"
  8. }
  9. function selection(selection: unknown) {
  10. if (!selection || typeof selection !== "object") return undefined
  11. const startLine = Number((selection as FileSelection).startLine)
  12. const startChar = Number((selection as FileSelection).startChar)
  13. const endLine = Number((selection as FileSelection).endLine)
  14. const endChar = Number((selection as FileSelection).endChar)
  15. if (![startLine, startChar, endLine, endChar].every(Number.isFinite)) return undefined
  16. return {
  17. startLine,
  18. startChar,
  19. endLine,
  20. endChar,
  21. } satisfies FileSelection
  22. }
  23. export function createCommentMetadata(input: PromptComment) {
  24. return {
  25. opencodeComment: {
  26. path: input.path,
  27. selection: input.selection,
  28. comment: input.comment,
  29. preview: input.preview,
  30. origin: input.origin,
  31. },
  32. }
  33. }
  34. export function readCommentMetadata(value: unknown) {
  35. if (!value || typeof value !== "object") return
  36. const meta = (value as { opencodeComment?: unknown }).opencodeComment
  37. if (!meta || typeof meta !== "object") return
  38. const path = (meta as { path?: unknown }).path
  39. const comment = (meta as { comment?: unknown }).comment
  40. if (typeof path !== "string" || typeof comment !== "string") return
  41. const preview = (meta as { preview?: unknown }).preview
  42. const origin = (meta as { origin?: unknown }).origin
  43. return {
  44. path,
  45. selection: selection((meta as { selection?: unknown }).selection),
  46. comment,
  47. preview: typeof preview === "string" ? preview : undefined,
  48. origin: origin === "review" || origin === "file" ? origin : undefined,
  49. } satisfies PromptComment
  50. }
  51. export function formatCommentNote(input: { path: string; selection?: FileSelection; comment: string }) {
  52. const start = input.selection ? Math.min(input.selection.startLine, input.selection.endLine) : undefined
  53. const end = input.selection ? Math.max(input.selection.startLine, input.selection.endLine) : undefined
  54. const range =
  55. start === undefined || end === undefined
  56. ? "this file"
  57. : start === end
  58. ? `line ${start}`
  59. : `lines ${start} through ${end}`
  60. return `The user made the following comment regarding ${range} of ${input.path}: ${input.comment}`
  61. }
  62. export function parseCommentNote(text: string) {
  63. const match = text.match(
  64. /^The user made the following comment regarding (this file|line (\d+)|lines (\d+) through (\d+)) of (.+?): ([\s\S]+)$/,
  65. )
  66. if (!match) return
  67. const start = match[2] ? Number(match[2]) : match[3] ? Number(match[3]) : undefined
  68. const end = match[2] ? Number(match[2]) : match[4] ? Number(match[4]) : undefined
  69. return {
  70. path: match[5],
  71. selection:
  72. start !== undefined && end !== undefined
  73. ? {
  74. startLine: start,
  75. startChar: 0,
  76. endLine: end,
  77. endChar: 0,
  78. }
  79. : undefined,
  80. comment: match[6],
  81. } satisfies PromptComment
  82. }