{"version":3,"file":"structured_data.cjs","names":[],"sources":["../../../src/batteries/tools/structured_data/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for transforming arrays and objects into tables and tabular text.\n *\n * @module @nhtio/adk/batteries/tools/structured_data\n *\n * @remarks\n * Pre-constructed bundled tools for the `structured_data` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { validator } from '@nhtio/validation'\nimport { isError, isObject } from '@nhtio/adk/guards'\n\nfunction csvEscape(value: unknown): string {\n  const str = value === null || value === undefined ? '' : String(value)\n  if (str.includes(',') || str.includes('\"') || str.includes('\\n') || str.includes('\\r')) {\n    return '\"' + str.replace(/\"/g, '\"\"') + '\"'\n  }\n  return str\n}\n\nfunction tsvEscape(value: unknown): string {\n  const str = value === null || value === undefined ? '' : String(value)\n  return str.replace(/\\t/g, ' ').replace(/\\r?\\n/g, ' ')\n}\n\nfunction mdEscape(value: unknown): string {\n  return String(value === null || value === undefined ? '' : value)\n    .replace(/\\|/g, '\\\\|')\n    .replace(/\\r?\\n/g, ' ')\n}\n\n/**\n * Convert a JSON array of objects into a formatted table.\n *\n * @remarks\n * Supports `markdown`, `csv`, and `tsv` output. Columns default to the keys of the first row;\n * supply `columns` to control which keys appear and in what order.\n */\nexport const formatTableTool = new Tool({\n  name: 'format_table',\n  description:\n    'Convert a JSON array of objects into a formatted table. Supports Markdown, CSV, and TSV output.',\n  inputSchema: validator.object({\n    data: validator.string().required().description('JSON array of objects as a string'),\n    format: validator\n      .string()\n      .valid('markdown', 'csv', 'tsv')\n      .required()\n      .description('Output format'),\n    columns: validator\n      .array()\n      .items(validator.string())\n      .optional()\n      .description(\n        'Column keys to include, in order. If omitted, all keys from the first row are used.'\n      ),\n  }),\n  handler: async (args) => {\n    const {\n      data,\n      format,\n      columns: explicitColumns,\n    } = args as {\n      data: string\n      format: 'markdown' | 'csv' | 'tsv'\n      columns?: string[]\n    }\n\n    let rows: unknown[]\n    try {\n      rows = JSON.parse(data)\n    } catch {\n      return 'Error: Invalid JSON input.'\n    }\n\n    if (!Array.isArray(rows)) return 'Error: Input must be a JSON array.'\n    if (rows.length === 0) return 'Empty array — no data to display.'\n\n    // Columns default to the first row's keys, but only an object row has keys. If columns aren't\n    // given and the first row isn't an object, there's nothing to tabulate — error clearly rather\n    // than throwing on `Object.keys(null)`.\n    if (!explicitColumns && !isObject(rows[0])) {\n      return 'Error: Cannot infer columns — the first row is not an object. Provide \"columns\", or pass an array of objects.'\n    }\n    const columns = explicitColumns ?? Object.keys(rows[0] as Record<string, unknown>)\n\n    // Read a cell safely: a null/primitive row has no properties, so it yields empty cells rather\n    // than throwing on `row[col]`.\n    const cell = (row: unknown, col: string): unknown =>\n      isObject(row) ? (row as Record<string, unknown>)[col] : undefined\n\n    if (format === 'csv') {\n      const lines = [columns.map(csvEscape).join(',')]\n      for (const row of rows) {\n        lines.push(columns.map((col) => csvEscape(cell(row, col))).join(','))\n      }\n      return lines.join('\\n')\n    }\n\n    if (format === 'tsv') {\n      const lines = [columns.map(tsvEscape).join('\\t')]\n      for (const row of rows) {\n        lines.push(columns.map((col) => tsvEscape(cell(row, col))).join('\\t'))\n      }\n      return lines.join('\\n')\n    }\n\n    const header = '| ' + columns.map(mdEscape).join(' | ') + ' |'\n    const separator = '| ' + columns.map(() => '---').join(' | ') + ' |'\n    const dataRows = rows.map((row) => {\n      return '| ' + columns.map((col) => mdEscape(cell(row, col))).join(' | ') + ' |'\n    })\n    return [header, separator, ...dataRows].join('\\n')\n  },\n})\n\n/**\n * Pretty-print or minify a JSON string.\n *\n * @remarks\n * Validates the input as JSON, then re-serialises it with the requested indentation. `indent` is\n * clamped to the range [0, 8]; `0` produces minified output.\n */\nexport const jsonFormatTool = new Tool({\n  name: 'json_format',\n  description: 'Pretty-print or minify a JSON string. Validates JSON and normalises whitespace.',\n  inputSchema: validator.object({\n    data: validator.string().required().description('JSON string to format'),\n    indent: validator\n      .number()\n      .default(2)\n      .description('Indentation spaces (0 = minify, default: 2). Max: 8.'),\n  }),\n  handler: async (args) => {\n    const { data, indent } = args as { data: string; indent: number }\n    try {\n      const parsed = JSON.parse(data)\n      return JSON.stringify(parsed, null, Math.max(0, Math.min(8, Math.floor(indent))))\n    } catch (err) {\n      return `Error: Invalid JSON — ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\nconst FORMAT_PATTERNS: Record<string, { pattern: RegExp; label: string }> = {\n  email: {\n    pattern: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/,\n    label: 'email address',\n  },\n  uuid: {\n    pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n    label: 'UUID (v1–v5)',\n  },\n  ipv4: {\n    pattern: /^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$/,\n    label: 'IPv4 address',\n  },\n  iso_date: {\n    pattern: /^\\d{4}-\\d{2}-\\d{2}$/,\n    label: 'ISO 8601 date (YYYY-MM-DD)',\n  },\n  iso_datetime: {\n    pattern: /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})?$/,\n    label: 'ISO 8601 datetime',\n  },\n  hex_color: {\n    pattern: /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,\n    label: 'CSS hex color',\n  },\n  phone_e164: {\n    pattern: /^\\+[1-9]\\d{1,14}$/,\n    label: 'E.164 phone number',\n  },\n  semver: {\n    pattern: /^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-.]+)?(\\+[0-9A-Za-z-.]+)?$/,\n    label: 'Semantic Version (SemVer)',\n  },\n  integer: {\n    pattern: /^-?\\d+$/,\n    label: 'integer',\n  },\n  decimal: {\n    pattern: /^-?\\d+(\\.\\d+)?$/,\n    label: 'decimal number',\n  },\n  alphanumeric: {\n    pattern: /^[a-zA-Z0-9]+$/,\n    label: 'alphanumeric string',\n  },\n  slug: {\n    pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/,\n    label: 'URL slug',\n  },\n  hex: {\n    pattern: /^(0x)?[0-9a-fA-F]+$/,\n    label: 'hexadecimal string',\n  },\n  base64: {\n    pattern: /^[A-Za-z0-9+/]*={0,2}$/,\n    label: 'base64-encoded string',\n  },\n}\n\n/**\n * Check whether a string matches a known format.\n *\n * @remarks\n * Supported formats: `email`, `uuid` (v1–v5), `ipv4`, `iso_date`, `iso_datetime`, `hex_color`,\n * `phone_e164`, `semver`, `integer`, `decimal`, `alphanumeric`, `slug`, `hex`, `base64`.\n */\nexport const validateFormatTool = new Tool({\n  name: 'validate_format',\n  description:\n    'Check whether a string matches a known format (email, UUID, ISO date, hex colour, phone number, semver, slug, etc.).',\n  inputSchema: validator.object({\n    value: validator.string().required().description('The string to validate'),\n    format: validator\n      .string()\n      .valid(...Object.keys(FORMAT_PATTERNS))\n      .required()\n      .description(\n        `Format to validate against. One of: ${Object.keys(FORMAT_PATTERNS).join(', ')}`\n      ),\n  }),\n  handler: async (args) => {\n    const { value, format } = args as { value: string; format: string }\n    const def = FORMAT_PATTERNS[format]\n    if (!def) {\n      return `Error: Unknown format \"${format}\". Supported: ${Object.keys(FORMAT_PATTERNS).join(', ')}`\n    }\n    const valid = def.pattern.test(value)\n    return valid\n      ? `Valid: \"${value}\" is a valid ${def.label}.`\n      : `Invalid: \"${value}\" is not a valid ${def.label}.`\n  },\n})\n"],"mappings":"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"}