Introduction
The idea for DialectMorph came to me when I initially tried to encapsulate a function for making an API call in an object using TypeScript. However, I later discovered that the API only supported Python, so I had to use AI agents to help me transpile the code from TypeScript to Python. This challenge inspired me to create a CLI tool that would simplify this process, essentially acting as a CLI wrapper for AI-driven code transpilation, which led to the development of DialectMorph.
Tech Stack Used
The entire project is based on TypeScript with different libraries that support the project, the following libraries were used in the codebase
-
Commander.js
Commander.js helped me configure the basic requirements for the CLI, I will talk in detail about Commander.js below -
Figlet
Ascii Text Generation For CLI Tool -
Chalk
Library for styling tools for the terminal -
Groq SDK
This is the Software Development Kit that is used to interact with Groq API
I used the singleton pattern here to instantiate the Groq Client because having more than one client during runtime might lead to unexpected errors -
Ora
This was used to make the terminal spinner -
VHS
This tool was used to make the demo video for the CLI tool -
Prettier
This tool was used to maintain consistent formatting, It was implemented along with a CI pipeline to ensure the code was formatted before being merged/pushed to the repo
Commander.js
This CLI tool uses commander extensively, so before going further
into the codebase, I would like to discuss how Commander works
Getting Started With Commander
To get started, create a commander object that would be later used to run the CLI tool
import Commander from "Commander"
const program = new Commander()
Configuration Methods
Commander library provides various methods to configure how the CLI tool would work, the ones that I use to make this tool can be described below
.version()
This command is used to specify the version of the CLI tool that is being used and provides the following options to the user
cli-tool -V
cli-tool --version
.name()
This command is used to specify the name of the CLI tool that is being used
.usage()
This command is used to specify how the user would use the CLI tool, it is usually placed at the first line when the -h or –help method is called with the tool
cli-tool -h
Output:
usage: cli-tool <input-file> -o <output-file>
-
.description()
This command is used to put the description for the CLI tool, it is displayed once the -h or –help command is called
cli-tool -h
Output:
usage: cli-tool <input-file> -o <output-file>
Description: This is some random description
-
.option()
A CLI tool has 2 different types of options that you can provide it, one being a boolean and the other one being a value-based option
Boolean Option
This option doesn’t need to have an argument provided to it to work
.option("-d,--display","Used to display some information")
Value-Based Option
This option needs to have an argument provided to it to work
.option("-o, --output <output_file>","Provide the output file for the CLI tool)
All of these options can be accessed via the following command and be used in the program based on the logic that you want
program.options.output()
The above code will output the value provided to the argument
-
.argument()
Defines a single argument with a placeholder for a command.
You specify whether it’s required or optional using angle brackets <> (required) or square brackets .
program
.command('run')
.argument('<file>', 'file to process') // 'file' is a required argument
.action((file) => {
console.log(`Processing file: ${file}`);
});
.arguments()
Defines multiple arguments, especially useful when you don’t need specific names for each argument.
program
.command('copy')
.arguments('<source> <destination>') // Both are required
.action((source, destination) => {
console.log(`Copying from ${source} to ${destination}`);
});
.parse()
.parse() is called without arguments, and it automatically parses process.argv, which contains all the arguments passed to your script, in my program I have used Bun to get the arguments
program.parse(Bun.argv)
Logic Flow
The Logic Flow of the program is as follows
- The input file(s) are inputted in the CLI tool
- The output language option is provided
- Optional arguments, including model or API key can be provided
- Program fetches the input file, calls an API call on Groq
- The result from Groq API is stored in the files under the transpiledFiles
Issues Encountered
As I delved into the intricacies of code transpilation and API integration, I found myself facing a multitude of challenges that tested my problem-solving skills and pushed me to expand my technical knowledge
The issues are as follows :
- Getting The Singleton Instantiation Right for the Groq Client
This issue took me a long time to get right, the issue was occurring because I wasn’t able to get the API_KEY as an argument in the instantiation for the singleton, however, the thing that helped me solve was making a helper function to address the instantiation
it was a tough one but I eventually got it right.
- Getting the binary to run on different machines
This was one of the most interesting issues I’ve worked on, as it required reproducing the problem on a Virtual Machine to identify what was going wrong. Despite using the bun link command, the binary still wouldn’t run. The challenge was that the binary worked fine on my local machine, so to troubleshoot without disrupting my working code, I cloned the repo on a VM. I successfully reproduced the issue and quickly found the solution: the problem was that the files weren’t being transpiled from TypeScript to JavaScript because the bun run build command hadn’t been executed before using bun link.
Conclusion
The development of DialectMorph has been an informative journey, transforming a personal need for code transpilation into a robust CLI tool that bridges multiple programming languages. This project solved the initial challenge of converting TypeScript to Python and evolved into a versatile utility that can assist developers across various language ecosystems.
Source link
lol