As of this week, my project Codeshift - a command line LLM-powered programming language translator - is finally available on npmjs.com!
Publishing For The First Time
This was my first time publishing a package on npm. The process was pretty straightforward.
First, I signed up for an account on npmjs.com and authenticated my npm CLI with my account using a "publish" type access token generated from the website.
I wanted to do a scoped release, i.e. I wanted to use my username as a namespace for the package - I think it keeps things nice and organized.
I began by reading the NPM documentation.
Reading through the package.json
documentation for the first time, I saw I needed to set the main
key, which points to the entry-point of the program and when your package is require()
d in a file it uses the exports from the file it's set to - though it doesn't really do anything for my project since my main module doesn't export anything, it didn't seem right to leave it to be set by default to index.js
which doesn't exist in my project. While reading through the docs I also ended up learning the difference between a package and a module, which was some nice bonus info.
Version 1.0.0
The rest of my package.json
was already configured using npm init
, so all I had to do was do a version release and then publish it, setting the access to public:
npm version 1.0.0
npm publish --access public
User Testing
I got my friend Peter to test my tool and we ran into trouble pretty much right away - the tool looked for a .env
file in the current directory meaning if the user wanted to use it on a project they'd have to add their API key and the provider base URL to the .env
file for the project. I thought this was a pretty primitive implementation and didn't like the idea of mixing up the tool's required environment variables with others in the directory - I mean, API_KEY
? That's pretty much guaranteed to conflict with existing variable. So I chose to move the required secrets into a config file called .codeshift.config.toml
, the idea being to mirror config files like eslint.config.mjs
, except you'd have to put it in .gitignore since it includes secrets.
Later, while testing with my friend Krins, he asked me for help figuring out how to get his tool to work without having to prefix npx
, and I told him npm i -g
should do the trick - but it didn't work, which made me question my own understanding of the command. Turns out I was wrong, and you actually need to run npm link <package>
. I remember running npm link codeshift
at some point but I also later ran npm unlink
, which is why I assumed the npm i -g
is what allowed me to use it without the prefix, but I guess something just went wrong when unlinking. Either way, since the feature seems kind of buggy I just decided keep it simple and update my README and prefix npx
to the usage instructions.
Update: So the reason my tool was able to run without prefixing npx
is that I added the bin
key to my package.json
:
{
"bin": {
"myapp": "bin/cli.js"
}
}
Automating Publishing to NPM with GitHub Actions
I also created a GitHub Actions workflow that publishes a new version to NPM when I create a release on GitHub. Thanks to GitHub's documentation this was very straightforward. I just added a new workflow file and got it working within minutes:
name: Release
on:
release:
types: [published]
jobs:
npmjs:
name: Publish package to npm
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x]
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- name: Setup .npmrc file to publish to npm
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
registry-url: "https://registry.npmjs.org"
- run: npm ci
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Installation
Now that the tool is on npm, it can be installed with npm -i @uday-rana/codeshift
. When first run with npx codeshift
, it will generate a .codeshift.config.toml
file in your current directory, where you can set up the API key and base URL for the LLM provider of your choice.
Then, you can use it like so:
npx codeshift [options] <output-language> <input-files...>
And pass in these arguments:
-
<output-language>
: The desired language to convert source files to -
<input-files...>
: Paths to the source files, separated by spaces
The tool also supports the following options:
-
-o, --output-file
: Specify filename to write output to -
-t, --token-usage
: Display the number of tokens used by the AI for processing -
-s, --stream
: Stream the response from the LLM -
-h, --help
: Display the help message explaining usage, options, and arguments -
-v, --version
: Display the program name and version number
So using it looks something like this:
# Converts a JavaScript file (index.js) to Go, saving the output in index.go
npx codeshift -o index.go go examples/index.js
That's it for this post, thanks for reading! Also, if you'd like to help out, contributions are welcome!
uday-rana / codeshift
A command-line tool that translates source code files into a chosen programming language.
codeshift
Codeshift is a command-line tool to translate and transform source code files between programming languages.
Features
- Select output language to convert source code into
- Support for multiple input files
- Output results to a file or stream directly to
stdout
- Customize model and provider selection for optimal performance
- Supports leading AI providers
Requirements
- Node.js (Requires Node.js 20.17.0+)
- An API key from any of the following providers:
- OpenAI
- OpenRouter
- Groq
- any other AI provider compatible with OpenAI's chat completions API endpoint
Installation
-
Run
npm install -g @uday-rana/codeshift
. -
Run
npx codeshift
. This will generate a.codeshift.config.toml
file in your current directory. -
In
.codeshift.config.toml
, set the base URL for your preferred provider and add your API key. It should look something like this:# .codeshift.config.toml [settings] baseUrl="https://openrouter.ai/api/v1" apiKey="sk-or-v1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" outputFile="xxxxxxxxxxx" model=""
…
Top comments (0)