(issueBody: string)
| 69 | } |
| 70 | |
| 71 | async function parseIssue(issueBody: string): Promise<IssueFields> { |
| 72 | const fields: Record<string, string> = {}; |
| 73 | const lines = issueBody.split('\n'); |
| 74 | |
| 75 | let currentField: string | null = null; |
| 76 | let currentValue: string[] = []; |
| 77 | |
| 78 | for (const line of lines) { |
| 79 | if (line.startsWith('### ')) { |
| 80 | if (currentField) { |
| 81 | fields[currentField] = currentValue.join('\n').trim(); |
| 82 | } |
| 83 | currentField = line.replace('### ', '').toLowerCase().replace(/\s+/g, '_'); |
| 84 | currentValue = []; |
| 85 | } else if (currentField) { |
| 86 | currentValue.push(line); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | if (currentField) { |
| 91 | fields[currentField] = currentValue.join('\n').trim(); |
| 92 | } |
| 93 | |
| 94 | // Apply field name mapping: map label-converted field names to actual field IDs |
| 95 | const mappedFields: IssueFields = {}; |
| 96 | for (const [key, value] of Object.entries(fields)) { |
| 97 | const mappedKey = FIELD_NAME_MAP[key] || key; |
| 98 | // Clean field value: unified handling of "_No response_" and empty values |
| 99 | const cleanedValue = cleanFieldValue(value); |
| 100 | |
| 101 | // If mapped field already exists, merge values (prefer mapped field) |
| 102 | if (mappedFields[mappedKey as keyof IssueFields] && mappedKey !== key) { |
| 103 | mappedFields[mappedKey as keyof IssueFields] = cleanedValue || mappedFields[mappedKey as keyof IssueFields]; |
| 104 | } else { |
| 105 | mappedFields[mappedKey as keyof IssueFields] = cleanedValue; |
| 106 | } |
| 107 | // Also keep original field name (for compatibility) |
| 108 | if (key !== mappedKey) { |
| 109 | mappedFields[key as keyof IssueFields] = cleanedValue; |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | return mappedFields; |
| 114 | } |
| 115 | |
| 116 | async function main() { |
| 117 | try { |
no test coverage detected