import type { DecodeOptions, Delimiter, EncodeOptions } from '../../toon/src' import type { InputSource } from './types' import * as fsp from 'node:fs/promises' import * as path from 'node:path' import process from 'node:process' import { consola } from 'consola' import { estimateTokenCount } from 'tokenx' import { decode, encode } from '../../toon/src' import { formatInputLabel, readInput } from './utils' export async function encodeToToon(config: { input: InputSource output?: string delimiter: Delimiter indent: number lengthMarker: NonNullable printStats: boolean }): Promise { const jsonContent = await readInput(config.input) let data: unknown try { data = JSON.parse(jsonContent) } catch (error) { throw new Error(`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`) } const encodeOptions: EncodeOptions = { delimiter: config.delimiter, indent: config.indent, lengthMarker: config.lengthMarker, } const toonOutput = encode(data, encodeOptions) if (config.output) { await fsp.writeFile(config.output, toonOutput, 'utf-8') const relativeInputPath = formatInputLabel(config.input) const relativeOutputPath = path.relative(process.cwd(), config.output) consola.success(`Encoded \`${relativeInputPath}\` → \`${relativeOutputPath}\``) } else { console.log(toonOutput) } if (config.printStats) { const jsonTokens = estimateTokenCount(jsonContent) const toonTokens = estimateTokenCount(toonOutput) const diff = jsonTokens - toonTokens const percent = ((diff / jsonTokens) * 100).toFixed(1) console.log() consola.info(`Token estimates: ~${jsonTokens} (JSON) → ~${toonTokens} (TOON)`) consola.success(`Saved ~${diff} tokens (-${percent}%)`) } } export async function decodeToJson(config: { input: InputSource output?: string indent: number strict: boolean }): Promise { const toonContent = await readInput(config.input) let data: unknown try { const decodeOptions: DecodeOptions = { indent: config.indent, strict: config.strict, } data = decode(toonContent, decodeOptions) } catch (error) { throw new Error(`Failed to decode TOON: ${error instanceof Error ? error.message : String(error)}`) } const jsonOutput = JSON.stringify(data, undefined, config.indent) if (config.output) { await fsp.writeFile(config.output, jsonOutput, 'utf-8') const relativeInputPath = formatInputLabel(config.input) const relativeOutputPath = path.relative(process.cwd(), config.output) consola.success(`Decoded \`${relativeInputPath}\` → \`${relativeOutputPath}\``) } else { console.log(jsonOutput) } }