@aashari/mcp-server-atlassian-jira
Version:
Node.js/TypeScript MCP server for Atlassian Jira. Equips AI systems (LLMs) with tools to list/get projects, search/get issues (using JQL/ID), and view dev info (commits, PRs). Connects AI capabilities directly into Jira project management and issue tracki
186 lines (185 loc) • 6.15 kB
JavaScript
;
// Test comment to verify edit functionality
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatUrl = formatUrl;
exports.formatHeading = formatHeading;
exports.formatBulletList = formatBulletList;
exports.formatSeparator = formatSeparator;
exports.formatNumberedList = formatNumberedList;
exports.formatDate = formatDate;
exports.formatPagination = formatPagination;
const logger_util_js_1 = require("./logger.util.js");
/**
* Markdown formatting utilities
*/
/**
* Standardized formatting utilities for consistent output across all CLI and Tool interfaces.
* These functions should be used by all formatters to ensure consistent formatting.
*/
/**
* Format a URL as a markdown link
* @param url - URL to format
* @param title - Link title
* @returns Formatted markdown link
*/
function formatUrl(url, title) {
if (!url) {
return 'Not available';
}
const linkTitle = title || url;
return `[${linkTitle}](${url})`;
}
/**
* Format a heading with consistent style
* @param text - Heading text
* @param level - Heading level (1-6)
* @returns Formatted heading
*/
function formatHeading(text, level = 1) {
const validLevel = Math.min(Math.max(level, 1), 6);
const prefix = '#'.repeat(validLevel);
return `${prefix} ${text}`;
}
/**
* Format a list of key-value pairs as a bullet list
* @param items - Object with key-value pairs
* @param keyFormatter - Optional function to format keys
* @returns Formatted bullet list
*/
function formatBulletList(items, keyFormatter) {
const lines = [];
for (const [key, value] of Object.entries(items)) {
if (value === undefined || value === null) {
continue;
}
const formattedKey = keyFormatter ? keyFormatter(key) : key;
const formattedValue = formatValue(value);
lines.push(`- **${formattedKey}**: ${formattedValue}`);
}
return lines.join('\n');
}
/**
* Format a value based on its type
* @param value - Value to format
* @returns Formatted value
*/
function formatValue(value) {
if (value === undefined || value === null) {
return 'Not available';
}
if (value instanceof Date) {
// Use toLocaleString for Dates
try {
return value.toLocaleString();
}
catch {
return 'Invalid date';
}
}
// Handle URL objects with url and title properties
if (typeof value === 'object' && value !== null && 'url' in value) {
const urlObj = value;
if (typeof urlObj.url === 'string') {
return formatUrl(urlObj.url, urlObj.title);
}
}
if (typeof value === 'string') {
// Check if it's a URL
if (value.startsWith('http://') || value.startsWith('https://')) {
return formatUrl(value);
}
// Check if it might be a date string and format it
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) {
try {
return new Date(value).toLocaleString();
}
catch {
return 'Invalid date string'; // Or return original string?
}
}
return value;
}
if (typeof value === 'boolean') {
return value ? 'Yes' : 'No';
}
return String(value);
}
/**
* Format a separator line
* @returns Separator line
*/
function formatSeparator() {
return '---';
}
/**
* Format a numbered list of items
* @param items - Array of items to format
* @param formatter - Function to format each item
* @returns Formatted numbered list
*/
function formatNumberedList(items, formatter) {
if (items.length === 0) {
return 'No items.';
}
return items
.map((item, index) => formatter(item, index))
.join('\n\n' + formatSeparator() + '\n\n');
}
/**
* Format a date in a standardized way: YYYY-MM-DD HH:MM:SS UTC
* @param dateInput - ISO date string, Date object, or timestamp number
* @returns Formatted date string
*/
function formatDate(dateInput) {
if (dateInput === undefined || dateInput === null) {
return 'Not available';
}
try {
// Create Date object correctly from string, Date, or number (timestamp)
const date = dateInput instanceof Date ? dateInput : new Date(dateInput);
// Check if the date is valid after creation
if (isNaN(date.getTime())) {
return 'Invalid date input';
}
// Format: YYYY-MM-DD HH:MM:SS UTC
return date
.toISOString()
.replace('T', ' ')
.replace(/\.\d+Z$/, ' UTC');
}
catch {
return 'Invalid date';
}
}
/**
* Format pagination information in a standardized way for CLI output.
* Includes separator, item counts, availability message, next page instructions, and timestamp.
* @param pagination - The ResponsePagination object containing pagination details.
* @returns Formatted pagination footer string for CLI.
*/
function formatPagination(pagination) {
const methodLogger = logger_util_js_1.Logger.forContext('utils/formatter.util.ts', 'formatPagination');
const parts = [formatSeparator()]; // Start with separator
const { count = 0, hasMore, nextCursor, total } = pagination;
// Showing count and potentially total
if (total !== undefined && total >= 0) {
parts.push(`*Showing ${count} of ${total} total items.*`);
}
else if (count >= 0) {
parts.push(`*Showing ${count} item${count !== 1 ? 's' : ''}.*`);
}
// More results availability
if (hasMore) {
parts.push('More results are available.');
}
// Prompt for the next action (using next startAt value for Jira)
if (hasMore && nextCursor) {
// nextCursor holds the next startAt value for OFFSET pagination
parts.push(`*Use --start-at ${nextCursor} to view more.*`);
}
// Add standard timestamp
parts.push(`*Information retrieved at: ${formatDate(new Date())}*`);
const result = parts.join('\n').trim(); // Join with newline
methodLogger.debug(`Formatted pagination footer: ${result}`);
return result;
}