Skip to main content
Glama
brendon92

Specialized AI Search Tools

by brendon92
conversion.ts8.57 kB
import { z } from 'zod'; import { parseString as parseXml, Builder as XmlBuilder } from 'xml2js'; import * as yaml from 'js-yaml'; import { parse as parseCsv } from 'csv-parse/sync'; import { stringify as stringifyCsv } from 'csv-stringify/sync'; import * as toml from '@iarna/toml'; import { BaseTool } from './base.js'; import { logger } from '../utils/logger.js'; /** * Supported data formats */ const formatEnum = z.enum(['json', 'xml', 'yaml', 'csv', 'toml']); type DataFormat = z.infer<typeof formatEnum>; /** * Conversion options schema */ const conversionOptionsSchema = z .object({ pretty: z.boolean().optional().default(true).describe('Pretty print output (with indentation)'), indent: z.number().int().min(0).max(8).optional().default(2).describe('Indentation spaces for pretty printing'), csvDelimiter: z.string().optional().default(',').describe('CSV delimiter character'), csvHeaders: z.boolean().optional().default(true).describe('CSV has headers in first row'), }) .optional(); /** * Type conversion tool schema */ const typeConversionSchema = z.object({ input: z.string().min(1).describe('Input data as string'), fromFormat: formatEnum.describe('Source data format'), toFormat: formatEnum.describe('Target data format'), options: conversionOptionsSchema, }); type TypeConversionParams = z.infer<typeof typeConversionSchema>; /** * TypeConversionTool - Convert between different data formats */ export class TypeConversionTool extends BaseTool<typeof typeConversionSchema> { readonly name = 'typeconversion'; readonly description = 'Convert data between different formats: JSON, XML, YAML, CSV, and TOML. Supports pretty printing, minification, and format-specific options like CSV delimiters and headers.'; readonly schema = typeConversionSchema; protected async execute(params: TypeConversionParams): Promise<string> { logger.info(`Converting from ${params.fromFormat} to ${params.toFormat}`); try { // Parse input to intermediate format (JavaScript object) const data = await this.parseInput(params.input, params.fromFormat, params.options); // Convert to target format const output = await this.formatOutput(data, params.toFormat, params.options); logger.info(`Conversion completed successfully`); return output; } catch (error) { throw new Error( `Conversion failed: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Parse input string to JavaScript object */ private async parseInput( input: string, format: DataFormat, options?: z.infer<typeof conversionOptionsSchema> ): Promise<any> { switch (format) { case 'json': return this.parseJson(input); case 'xml': return await this.parseXmlToObject(input); case 'yaml': return this.parseYaml(input); case 'csv': return this.parseCsvToObject(input, options); case 'toml': return this.parseToml(input); default: throw new Error(`Unsupported input format: ${format}`); } } /** * Format JavaScript object to output string */ private async formatOutput( data: any, format: DataFormat, options?: z.infer<typeof conversionOptionsSchema> ): Promise<string> { switch (format) { case 'json': return this.formatJson(data, options); case 'xml': return await this.formatXml(data, options); case 'yaml': return this.formatYaml(data, options); case 'csv': return this.formatCsv(data, options); case 'toml': return this.formatToml(data); default: throw new Error(`Unsupported output format: ${format}`); } } /** * Parse JSON string */ private parseJson(input: string): any { try { return JSON.parse(input); } catch (error) { throw new Error(`Invalid JSON: ${error instanceof Error ? error.message : 'Parse error'}`); } } /** * Format data as JSON */ private formatJson(data: any, options?: z.infer<typeof conversionOptionsSchema>): string { const indent = options?.pretty ? (options?.indent ?? 2) : 0; return JSON.stringify(data, null, indent); } /** * Parse XML string to object */ private async parseXmlToObject(input: string): Promise<any> { return new Promise((resolve, reject) => { parseXml( input, { explicitArray: false, mergeAttrs: true, explicitRoot: false, }, (error, result) => { if (error) { reject(new Error(`Invalid XML: ${error.message}`)); } else { resolve(result); } } ); }); } /** * Format data as XML */ private async formatXml(data: any, options?: z.infer<typeof conversionOptionsSchema>): Promise<string> { const builder = new XmlBuilder({ renderOpts: { pretty: options?.pretty ?? true, indent: ' '.repeat(options?.indent ?? 2), }, }); // Wrap data in root element if it's not already wrapped const wrappedData = typeof data === 'object' && !Array.isArray(data) ? data : { root: data }; return builder.buildObject(wrappedData); } /** * Parse YAML string */ private parseYaml(input: string): any { try { return yaml.load(input); } catch (error) { throw new Error(`Invalid YAML: ${error instanceof Error ? error.message : 'Parse error'}`); } } /** * Format data as YAML */ private formatYaml(data: any, options?: z.infer<typeof conversionOptionsSchema>): string { return yaml.dump(data, { indent: options?.indent ?? 2, lineWidth: -1, // No line wrapping noRefs: true, // Don't use references }); } /** * Parse CSV string to array of objects */ private parseCsvToObject(input: string, options?: z.infer<typeof conversionOptionsSchema>): any[] { try { const records = parseCsv(input, { delimiter: options?.csvDelimiter ?? ',', columns: options?.csvHeaders ?? true, skip_empty_lines: true, trim: true, }); return records; } catch (error) { throw new Error(`Invalid CSV: ${error instanceof Error ? error.message : 'Parse error'}`); } } /** * Format data as CSV */ private formatCsv(data: any, options?: z.infer<typeof conversionOptionsSchema>): string { try { // Ensure data is an array const arrayData = Array.isArray(data) ? data : [data]; if (arrayData.length === 0) { return ''; } return stringifyCsv(arrayData, { delimiter: options?.csvDelimiter ?? ',', header: options?.csvHeaders ?? true, }); } catch (error) { throw new Error(`CSV formatting failed: ${error instanceof Error ? error.message : 'Format error'}`); } } /** * Parse TOML string */ private parseToml(input: string): any { try { return toml.parse(input); } catch (error) { throw new Error(`Invalid TOML: ${error instanceof Error ? error.message : 'Parse error'}`); } } /** * Format data as TOML */ private formatToml(data: any): string { try { // TOML requires an object at the root level if (typeof data !== 'object' || Array.isArray(data)) { throw new Error('TOML format requires an object at the root level'); } return toml.stringify(data); } catch (error) { throw new Error(`TOML formatting failed: ${error instanceof Error ? error.message : 'Format error'}`); } } }

Implementation Reference

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/brendon92/mcp-server'

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