(input: CreateTaskInput)
| 126 | |
| 127 | function mergeDescriptionParts(parts: Array<string | null | undefined>): string | undefined { |
| 128 | const merged: string[] = []; |
| 129 | const seen = new Set<string>(); |
| 130 | for (const part of parts) { |
| 131 | const trimmed = part?.trim(); |
| 132 | if (!trimmed || seen.has(trimmed)) { |
| 133 | continue; |
| 134 | } |
| 135 | merged.push(part!); |
| 136 | seen.add(trimmed); |
| 137 | } |
| 138 | return merged.length > 0 ? merged.join('\n\n') : undefined; |
| 139 | } |
| 140 | |
| 141 | function normalizeCreateTaskInput(input: CreateTaskInput): Required<Pick<CreateTaskInput, 'title'>> & Pick<CreateTaskInput, 'description' | 'priority'> { |
| 142 | const rawTitle = input.title; |
| 143 | const compactTitle = compactWhitespace(rawTitle); |
| 144 | if (compactTitle.length === 0) { |
| 145 | throw new ValidationError('Task title is required'); |
| 146 | } |
| 147 | |
| 148 | if (!needsBodySplit(rawTitle, compactTitle)) { |
| 149 | return { |
| 150 | title: normalizeTaskTitle(rawTitle), |
| 151 | description: input.description, |
no test coverage detected