Writing Small Automation Script: From proto to type definition

Tulusibrahim
JavaScript in Plain English
4 min readOct 23, 2023

--

Photo by Lenny Kuhne on Unsplash

Background

The project just started, and the team decided to use nextjs with graphql, both graphql client and graphql server. But, we also have a separate backend that is written in Go. For me, it’s not very common to use those stacks since I feel it feels redundant because we have both graphql server and a dedicated backend.

Then, within the graphql type definitions, we would like to define the definition the same as the proto file that we have from the backend. Here are the problems:

  • The message within the proto is using snake_case. For instance:

But within the type definitions, we want it to use camelCase. So if the case like above, we want to transform it to:

At first, it did not feel tidy to change the type from user_id to userId, usually I just used ctrl+d command within the vscode to select all the same occurrences and change them, but as the feature added up, we needed to define more of type definition, and it felt tedious. So I initiated to create some script to run if there was an update or a new proto file came up and automate those steps instantly.

Solution

First I created a js file in the root project, so I could call it later by just node {filename} after that, I start by asking where is the file location, so I can get the whole data to process

after that, I will use regex to replace all the occurrences of word message with type

to change type from int32 or int64 to Number type for all occurrences

and to change the snake_case to camelCase here’s how I do it

and to transform the string/bool/float is pretty much the same as int32

to cover the case where there is repeated syntax, here’s how I do it

after that process is finished, I write the result into a new generated file called generated.typeDef.ts, and close the process with process.exit(0)

Full working code:

const readline = require('readline');
const fs = require('fs').promises;
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});

async function transformProto() {
rl.question('Where is the file path?', async function (src) {
const data = await fs.readFile(src, 'utf8');
let result = data
.replace(/message/g, 'type')
.replace(/int32\s+(\w+)\s*=\s*(\d+);/g, '$1: Int')
.replace(/int64\s+(\w+)\s*=\s*(\d+);/g, '$1: Int')
.replace(/([_][a-z])/g, (group) => group.toUpperCase().replace('-', '').replace('_', ''))
.replace(/string\s+(\w+)\s*=\s*(\d+);/g, '$1: String')
.replace(/bool\s+(\w+)\s*=\s*(\d+);/g, '$1: Boolean')
.replace(/float\s+(\w+)\s*=\s*(\d+);/g, '$1: Float')
.replace(/repeated\s+(\w+)\s+(\w+)\s*=\s*\d+;/g, '$2: [$1]')

await fs.writeFile(
'generated.typeDef.ts',
'export const typeDef `' + result + '`;\n',
'utf8'
);

console.log('✅ Success generate file to ./generated.typeDef.ts');
rl.close();
process.exit(0);
})
}
transformProto()

In Plain English

Thank you for being a part of our community! Before you go:

--

--