orca/src/shared/orchestration-task-display.ts

54 lines
1.6 KiB
TypeScript

export const ORCHESTRATION_TASK_TITLE_MAX_LENGTH = 80
export const ORCHESTRATION_DISPLAY_NAME_MAX_LENGTH = 160
export type OrchestrationTaskDisplayMetadata = {
taskTitle: string
displayName: string
}
export function buildOrchestrationTaskDisplayMetadata(input: {
spec: string
taskTitle?: string | null
displayName?: string | null
}): OrchestrationTaskDisplayMetadata {
const taskTitle =
normalizeSingleLine(input.taskTitle, ORCHESTRATION_TASK_TITLE_MAX_LENGTH) ||
deriveTaskTitleFromSpec(input.spec)
const displayName =
normalizeSingleLine(input.displayName, ORCHESTRATION_DISPLAY_NAME_MAX_LENGTH) || taskTitle
return { taskTitle, displayName }
}
function deriveTaskTitleFromSpec(spec: string): string {
for (const line of spec.split(/\r?\n/)) {
const title = normalizeSingleLine(line, ORCHESTRATION_TASK_TITLE_MAX_LENGTH)
if (title) {
return title
}
}
return normalizeSingleLine(spec, ORCHESTRATION_TASK_TITLE_MAX_LENGTH)
}
function normalizeSingleLine(value: string | null | undefined, maxLength: number): string {
if (!value) {
return ''
}
const normalized = value.trim().replace(/\s+/g, ' ')
if (!normalized) {
return ''
}
if (normalized.length <= maxLength) {
return normalized
}
const body = trimDanglingHighSurrogate(normalized.slice(0, maxLength - 3)).trimEnd()
return `${body}...`
}
function trimDanglingHighSurrogate(value: string): string {
if (value.length === 0) {
return value
}
const lastCode = value.charCodeAt(value.length - 1)
return lastCode >= 0xd800 && lastCode <= 0xdbff ? value.slice(0, -1) : value
}