What We Are Building
In this tutorial, you will build a CLI tool called fconv that converts files between common formats:
- CSV to JSON
- JSON to CSV
- Markdown to HTML
- YAML to JSON
By the end, you will have a reusable, publishable npm package that runs from the terminal:
fconv input.csv --to json -o output.json
Project Setup
Create a new project directory and initialize it:
mkdir fconv && cd fconv
npm init -y
Install the dependencies we need:
npm install commander csv-parse csv-stringify js-yaml marked
- commander - CLI argument parsing
- csv-parse / csv-stringify - CSV reading and writing
- js-yaml - YAML parsing
- marked - Markdown to HTML conversion
Update package.json to add the bin entry:
{
"bin": {
"fconv": "./index.js"
},
"type": "module"
}
Building the CLI Entry Point
Create index.js with the argument parser:
#!/usr/bin/env node
import { Command } from "commander";
import { readFileSync, writeFileSync } from "fs";
import { convert } from "./converter.js";
const program = new Command();
program
.name("fconv")
.description("Convert files between formats")
.argument("", "Input file path")
.requiredOption("--to ", "Output format (json, csv, html, yaml)")
.option("-o, --output ", "Output file path")
.option("-p, --pretty", "Pretty print output", false)
.action((input, options) => {
const content = readFileSync(input, "utf-8");
const result = convert(content, input, options.to, options.pretty);
if (options.output) {
writeFileSync(options.output, result);
console.log(Converted: ${input} -> ${options.output});
} else {
console.log(result);
}
});
program.parse();
Implementing the Converter
Create converter.js with the conversion logic:
import { parse } from "csv-parse/sync";
import { stringify } from "csv-stringify/sync";
import yaml from "js-yaml";
import { marked } from "marked";
import { extname } from "path";
export function convert(content, inputPath, toFormat, pretty) {
const fromFormat = extname(inputPath).slice(1).toLowerCase();
const key = ${fromFormat}->${toFormat};
const converters = {
"csv->json": () => {
const records = parse(content, { columns: true, trim: true });
return JSON.stringify(records, null, pretty ? 2 : 0);
},
"json->csv": () => {
const data = JSON.parse(content);
return stringify(data, { header: true });
},
"md->html": () => marked(content),
"yaml->json": () => {
const data = yaml.load(content);
return JSON.stringify(data, null, pretty ? 2 : 0);
},
"json->yaml": () => yaml.dump(JSON.parse(content)),
};
const fn = converters[key];
if (!fn) throw new Error(Unsupported conversion: ${key});
return fn();
}
Testing Your Tool
Link the tool locally to test it:
npm link
Create a test CSV file test.csv:
name,age,city
Alice,30,New York
Bob,25,London
Charlie,35,Tokyo
Run the conversions:
# CSV to JSON
fconv test.csv --to json -p
# Output:
[
{ "name": "Alice", "age": "30", "city": "New York" },
{ "name": "Bob", "age": "25", "city": "London" },
{ "name": "Charlie", "age": "35", "city": "Tokyo" }
]
Save to a file:
fconv test.csv --to json -p -o test.json
Publishing to npm
To share your tool with the world:
- 1. Create an npm account at npmjs.com if you do not have one
- 2. Login from the terminal:
npm login - 3. Publish:
npm publish
Anyone can now install and use your converter:
npx fconv data.csv --to json -p
FAQ
Absolutely. Just add a new entry to the converters object in converter.js. The pattern is "from->to": () => convertedString.
For files over 100 MB, use streaming instead of readFileSync. Both csv-parse and csv-stringify support Node.js streams.
This tool focuses on text-based formats. For binary conversions, use Reformat's free online tools which handle PDF, images, and more.