Skip to main content
Glama
cristip73
by cristip73
field-utils.ts4.91 kB
/** * Utilities for handling Asana custom fields */ /** * Validates custom field values based on their type * @param fieldType The type of the custom field (enum, text, number, date, etc.) * @param value The value to validate * @returns {boolean} Whether the value is valid for the field type */ export function validateCustomFieldValue(fieldType: string, value: any): boolean { // Null values are valid for all field types (to clear a field) if (value === null) { return true; } switch (fieldType) { case 'text': return typeof value === 'string'; case 'number': return typeof value === 'number' && !isNaN(value); case 'enum': // Enum values should be strings (the GID of the enum option) return typeof value === 'string' && value.length > 0; case 'date': // Check if it's a valid date string in YYYY-MM-DD format if (typeof value !== 'string') return false; const dateRegex = /^\d{4}-\d{2}-\d{2}$/; if (!dateRegex.test(value)) return false; // Check if it's a valid date const date = new Date(value); return !isNaN(date.getTime()); case 'boolean': return typeof value === 'boolean'; case 'multi_enum': return Array.isArray(value) && value.every(item => typeof item === 'string' && item.length > 0); default: return true; // Allow unknown field types to pass validation } } /** * Formats custom field values for Asana API * @param customFields Object mapping field GIDs to their values * @param fieldMetadata Array of custom field metadata objects from Asana * @returns Formatted custom fields object */ export function formatCustomFieldsForUpdate(customFields: Record<string, any>, fieldMetadata: any[] = []): Record<string, any> { const formattedFields: Record<string, any> = {}; const metadataMap: Record<string, any> = {}; // Create a map of field GIDs to their metadata fieldMetadata.forEach(field => { metadataMap[field.gid] = field; }); // Process each custom field for (const [fieldGid, value] of Object.entries(customFields)) { const fieldMeta = metadataMap[fieldGid]; // Skip if we don't have metadata for this field if (!fieldMeta) { console.warn(`No metadata found for custom field ${fieldGid}, skipping validation`); formattedFields[fieldGid] = value; continue; } // Get the field type const fieldType = fieldMeta.resource_subtype || fieldMeta.type; // Validate the value based on the field type if (!validateCustomFieldValue(fieldType, value)) { throw new Error( `Invalid value for custom field "${fieldMeta.name}" (${fieldGid}). ` + `Expected type: ${fieldType}, received: ${typeof value}. ` + getCustomFieldFormatHint(fieldType) ); } // Format the value according to the field type formattedFields[fieldGid] = value; } return formattedFields; } /** * Gets formatting hint for a specific custom field type * @param fieldType The type of custom field * @returns A string with formatting guidance */ function getCustomFieldFormatHint(fieldType: string): string { switch (fieldType) { case 'enum': return "For enum fields, use the enum option GID (e.g., '12345') not the display name."; case 'date': return "Date fields should be in YYYY-MM-DD format (e.g., '2023-04-15')."; case 'number': return "Number fields should be numeric values (e.g., 42 or 3.14)."; case 'multi_enum': return "Multi-enum fields should be arrays of enum option GIDs (e.g., ['12345', '67890'])."; default: return ""; } } /** * Gets custom field metadata for a task * @param task Task object from Asana API * @returns Array of custom field metadata objects */ export function getCustomFieldMetadataFromTask(task: any): any[] { if (!task.custom_fields || !Array.isArray(task.custom_fields)) { return []; } return task.custom_fields.map(field => ({ gid: field.gid, name: field.name, resource_subtype: field.resource_subtype, type: field.type, enum_options: field.enum_options })); } /** * Parses custom fields input that might be a string * @param customFields The custom fields input (object or JSON string) * @returns Parsed custom fields object */ export function parseCustomFields(customFields: any): Record<string, any> { if (typeof customFields === 'string') { try { return JSON.parse(customFields); } catch (err) { throw new Error(`Invalid custom_fields format: ${(err as Error).message}. Expected valid JSON object mapping field GIDs to values.`); } } if (typeof customFields === 'object' && customFields !== null) { return customFields; } throw new Error("Invalid custom_fields format. Expected object mapping field GIDs to values."); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cristip73/mcp-server-asana'

If you have feedback or need assistance with the MCP directory API, please join our Discord server