import fs from 'fs'; import { formatJiraRichText } from './jiraRichText.js'; const SKIP_FIELD_IDS = new Set(['attachment']); const EASTERN_TIME_ZONE = 'America/New_York'; export function formatEasternDateTime(value) { const date = new Date(value); if (Number.isNaN(date.getTime())) { return String(value); } const formatted = new Intl.DateTimeFormat('en-US', { timeZone: EASTERN_TIME_ZONE, month: 'numeric', day: 'numeric', year: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true, }).format(date); const timeZoneName = new Intl.DateTimeFormat('en-US', { timeZone: EASTERN_TIME_ZONE, timeZoneName: 'short', }).formatToParts(date).find(part => part.type === 'timeZoneName')?.value || 'ET'; return `${formatted} ${timeZoneName}`; } export function formatEasternDate(value) { const date = new Date(value); if (Number.isNaN(date.getTime())) { return String(value); } return new Intl.DateTimeFormat('en-US', { timeZone: EASTERN_TIME_ZONE, month: 'numeric', day: 'numeric', year: 'numeric', }).format(date); } export function loadRequestTypeFields() { const path = './config/requestTypeFields.json'; if (!fs.existsSync(path)) { return { common: { displayFields: [] }, groups: {}, requestTypes: {} }; } return JSON.parse(fs.readFileSync(path, 'utf8')); } function resolveFieldEntry(entry, groups) { if (typeof entry === 'string' && groups[entry]) { return groups[entry].displayFields || []; } return [entry]; } export function getDisplayFieldsForRequestType(requestTypeId, fieldMap = loadRequestTypeFields()) { const key = String(requestTypeId); const typeConfig = fieldMap.requestTypes?.[key]; if (!typeConfig) { return fieldMap.common?.displayFields || []; } const groups = fieldMap.groups || {}; const resolved = []; if (typeConfig.includeCommon !== false) { resolved.push(...(fieldMap.common?.displayFields || [])); } for (const groupRef of typeConfig.groups || []) { const groupFields = groups[groupRef]?.displayFields || []; resolved.push(...groupFields); } for (const field of typeConfig.displayFields || []) { resolved.push(...resolveFieldEntry(field, groups)); } const seen = new Set(); return resolved.filter(field => { const dedupeKey = field.path || field.fieldId; if (!dedupeKey || seen.has(dedupeKey) || SKIP_FIELD_IDS.has(field.fieldId)) { return false; } seen.add(dedupeKey); return true; }); } export function formatFieldValue(value, format) { if (value == null || value === '') { return null; } switch (format) { case 'option': return value.value ?? value.name ?? String(value); case 'user': return value.displayName ?? value.emailAddress ?? String(value); case 'users': if (!Array.isArray(value)) { return formatFieldValue(value, 'user'); } return value.map(item => formatFieldValue(item, 'user')).filter(Boolean).join(', '); case 'datetime': return formatEasternDateTime(value); case 'date': return formatEasternDate(value); case 'cmdb': if (Array.isArray(value)) { return value.map(item => item.label || item.name || item.objectKey || item.value).filter(Boolean).join(', '); } return value.label || value.name || value.objectKey || String(value); case 'multiselect': case 'multicheckboxes': if (!Array.isArray(value)) { return String(value); } return value.map(item => item.value || item.label || String(item)).join(', '); case 'cascading': if (value.child) { return `${value.value} → ${value.child.value}`; } return value.value ?? String(value); case 'textarea': case 'text': default: if (typeof value === 'object') { const richText = formatJiraRichText(value); return richText || value.displayName || value.value || value.name || null; } return formatJiraRichText(value) || null; } } export function getFieldValueFromTicket(jiraTicket, fieldDef) { if (fieldDef.path) { return fieldDef.path.split('.').reduce((current, part) => current?.[part], jiraTicket); } const fieldId = fieldDef.fieldId; if (!fieldId) { return null; } if (fieldId === 'summary' || fieldId === 'description' || fieldId === 'priority' || fieldId === 'created' || fieldId === 'updated') { const fields = jiraTicket.issue?.fields || {}; return fields[fieldId]; } return jiraTicket.issue?.fields?.[fieldId] ?? null; } export function buildDetailLinesForRequestType(jiraTicket, requestTypeId, fieldMap = loadRequestTypeFields()) { const fields = getDisplayFieldsForRequestType(requestTypeId, fieldMap); const lines = []; for (const fieldDef of fields) { const rawValue = getFieldValueFromTicket(jiraTicket, fieldDef); const formatted = formatFieldValue(rawValue, fieldDef.format); if (formatted) { lines.push({ label: fieldDef.label, value: formatted, format: fieldDef.format }); } } return lines; }