src / tools / utilityTools.ts
src / tools / utilityTools.ts
/**
* Utility Tools
* Provides JSON merging, regex testing, URL building, hashing, and UUID generation/validation.
*/
import crypto from 'crypto';
import { z } from 'zod';
import fs from 'fs/promises';
import path from 'path';
// Zod schemas for validation
const jsonMergeSchema = z.object({
files: z.array(z.string().min(1)),
output_path: z.string().optional(),
});
const regexTestSchema = z.object({
pattern: z.string().min(1),
text: z.string().min(1),
flags: z.string().optional(),
});
const urlBuildSchema = z.object({
base_url: z.string().url(),
params: z.record(z.union([z.string(), z.number(), z.boolean()])),
});
const hashGenerateSchema = z.object({
content: z.union([z.string(), z.instanceof(Buffer)]),
algorithm: z.enum(['md5', 'sha1', 'sha256', 'sha512']).optional().default('sha256'),
});
/**
* Merge multiple JSON files into one object.
*/
export async function json_merge(files: string[], output_path?: string): Promise<{ merged_object: any; errors: Array<{ file: string; error: string }> }> {
const validated = jsonMergeSchema.parse({ files, output_path });
let mergedObject: any = {};
const errors: Array<{ file: string; error: string }> = [];
try {
for (const file of validated.files) {
try {
await fs.access(file);
const content = await fs.readFile(file, 'utf-8');
const parsed = JSON.parse(content);
// Deep merge the object
mergedObject = deepMerge(mergedObject, parsed);
} catch (error) {
errors.push({ file, error: error instanceof Error ? error.message : String(error) });
}
}
// Write to output file if specified
if (validated.output_path) {
try {
await fs.mkdir(path.dirname(validated.output_path), { recursive: true });
await fs.writeFile(validated.output_path, JSON.stringify(mergedObject, null, 2));
} catch (error) {
errors.push({ file: validated.output_path, error: error instanceof Error ? error.message : String(error) });
}
}
return { merged_object: mergedObject, errors };
} catch (error) {
throw new Error(`JSON merge failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Test a regex pattern against text.
*/
export async function regex_test(pattern: string, text: string, flags?: string): Promise<{ matches: Array<{ text: string; index: number }>; match_count: number }> {
const validated = regexTestSchema.parse({ pattern, text, flags });
try {
const regex = new RegExp(validated.pattern, validated.flags || 'g');
const matches: Array<{ text: string; index: number }> = [];
let match;
while ((match = regex.exec(validated.text)) !== null) {
matches.push({ text: match[0], index: match.index });
// Prevent infinite loop for zero-length matches
if (match[0].length === 0) {
regex.lastIndex++;
}
}
return { matches, match_count: matches.length };
} catch (error) {
throw new Error(`Regex test failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Build a URL with query parameters.
*/
export async function url_build(base_url: string, params: Record<string, any>): Promise<{ built_url: string }> {
const validated = urlBuildSchema.parse({ base_url, params });
try {
const url = new URL(validated.base_url);
for (const [key, value] of Object.entries(validated.params)) {
if (value !== null && value !== undefined) {
url.searchParams.append(key, String(value));
}
}
return { built_url: url.toString() };
} catch (error) {
throw new Error(`URL building failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Generate a hash of content.
*/
export async function hash_generate(content: string | Buffer, algorithm?: 'md5' | 'sha1' | 'sha256' | 'sha512'): Promise<{ hash: string; algorithm_used: string }> {
const validated = hashGenerateSchema.parse({ content, algorithm });
try {
const hash = crypto.createHash(validated.algorithm || 'sha256');
hash.update(typeof validated.content === 'string' ? Buffer.from(validated.content) : validated.content);
return {
hash: hash.digest('hex'),
algorithm_used: validated.algorithm || 'sha256'
};
} catch (error) {
throw new Error(`Hash generation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Generate a UUID.
*/
export async function uuid_generate(): Promise<{ uuid: string }> {
const uuid = crypto.randomUUID();
return { uuid };
}
/**
* Validate a UUID format.
*/
export async function uuid_validate(id: string): Promise<{ valid: boolean }> {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return { valid: uuidRegex.test(id) };
}
/**
* Deep merge two objects.
*/
function deepMerge(target: any, source: any): any {
const result = { ...target };
for (const key of Object.keys(source)) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
if (key in target) {
result[key] = deepMerge(target[key], source[key]);
} else {
result[key] = { ...source[key] };
}
} else {
result[key] = source[key];
}
}
return result;
}
/**
* Utility Tools
* Provides JSON merging, regex testing, URL building, hashing, and UUID generation/validation.
*/
import crypto from 'crypto';
import { z } from 'zod';
import fs from 'fs/promises';
import path from 'path';
// Zod schemas for validation
const jsonMergeSchema = z.object({
files: z.array(z.string().min(1)),
output_path: z.string().optional(),
});
const regexTestSchema = z.object({
pattern: z.string().min(1),
text: z.string().min(1),
flags: z.string().optional(),
});
const urlBuildSchema = z.object({
base_url: z.string().url(),
params: z.record(z.union([z.string(), z.number(), z.boolean()])),
});
const hashGenerateSchema = z.object({
content: z.union([z.string(), z.instanceof(Buffer)]),
algorithm: z.enum(['md5', 'sha1', 'sha256', 'sha512']).optional().default('sha256'),
});
/**
* Merge multiple JSON files into one object.
*/
export async function json_merge(files: string[], output_path?: string): Promise<{ merged_object: any; errors: Array<{ file: string; error: string }> }> {
const validated = jsonMergeSchema.parse({ files, output_path });
let mergedObject: any = {};
const errors: Array<{ file: string; error: string }> = [];
try {
for (const file of validated.files) {
try {
await fs.access(file);
const content = await fs.readFile(file, 'utf-8');
const parsed = JSON.parse(content);
// Deep merge the object
mergedObject = deepMerge(mergedObject, parsed);
} catch (error) {
errors.push({ file, error: error instanceof Error ? error.message : String(error) });
}
}
// Write to output file if specified
if (validated.output_path) {
try {
await fs.mkdir(path.dirname(validated.output_path), { recursive: true });
await fs.writeFile(validated.output_path, JSON.stringify(mergedObject, null, 2));
} catch (error) {
errors.push({ file: validated.output_path, error: error instanceof Error ? error.message : String(error) });
}
}
return { merged_object: mergedObject, errors };
} catch (error) {
throw new Error(`JSON merge failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Test a regex pattern against text.
*/
export async function regex_test(pattern: string, text: string, flags?: string): Promise<{ matches: Array<{ text: string; index: number }>; match_count: number }> {
const validated = regexTestSchema.parse({ pattern, text, flags });
try {
const regex = new RegExp(validated.pattern, validated.flags || 'g');
const matches: Array<{ text: string; index: number }> = [];
let match;
while ((match = regex.exec(validated.text)) !== null) {
matches.push({ text: match[0], index: match.index });
// Prevent infinite loop for zero-length matches
if (match[0].length === 0) {
regex.lastIndex++;
}
}
return { matches, match_count: matches.length };
} catch (error) {
throw new Error(`Regex test failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Build a URL with query parameters.
*/
export async function url_build(base_url: string, params: Record<string, any>): Promise<{ built_url: string }> {
const validated = urlBuildSchema.parse({ base_url, params });
try {
const url = new URL(validated.base_url);
for (const [key, value] of Object.entries(validated.params)) {
if (value !== null && value !== undefined) {
url.searchParams.append(key, String(value));
}
}
return { built_url: url.toString() };
} catch (error) {
throw new Error(`URL building failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Generate a hash of content.
*/
export async function hash_generate(content: string | Buffer, algorithm?: 'md5' | 'sha1' | 'sha256' | 'sha512'): Promise<{ hash: string; algorithm_used: string }> {
const validated = hashGenerateSchema.parse({ content, algorithm });
try {
const hash = crypto.createHash(validated.algorithm || 'sha256');
hash.update(typeof validated.content === 'string' ? Buffer.from(validated.content) : validated.content);
return {
hash: hash.digest('hex'),
algorithm_used: validated.algorithm || 'sha256'
};
} catch (error) {
throw new Error(`Hash generation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Generate a UUID.
*/
export async function uuid_generate(): Promise<{ uuid: string }> {
const uuid = crypto.randomUUID();
return { uuid };
}
/**
* Validate a UUID format.
*/
export async function uuid_validate(id: string): Promise<{ valid: boolean }> {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return { valid: uuidRegex.test(id) };
}
/**
* Deep merge two objects.
*/
function deepMerge(target: any, source: any): any {
const result = { ...target };
for (const key of Object.keys(source)) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
if (key in target) {
result[key] = deepMerge(target[key], source[key]);
} else {
result[key] = { ...source[key] };
}
} else {
result[key] = source[key];
}
}
return result;
}