Skip to content

Commit

Permalink
Merge pull request #9 from launchql/upgrade/cli
Browse files Browse the repository at this point in the history
upgrade to use inquirerer
  • Loading branch information
pyramation committed May 3, 2024
2 parents 8bf6ed5 + 70e3745 commit 4cac67b
Show file tree
Hide file tree
Showing 21 changed files with 758 additions and 130 deletions.
77 changes: 44 additions & 33 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,50 +45,61 @@ pg-proto-parser --inFile pg_query.proto --outDir out

## Usage

After installation, you can run the `pg-proto-parser` command as follows:
After installation, you can run the `pg-proto-parser` command for code generation as follows:

### codegen

```bash
pg-proto-parser --inFile <path-to-proto> --outDir <output-directory>
pg-proto-parser codegen --inFile <path-to-proto> --outDir <output-directory> \
[--enums] [--enumsJSON] [--typeUnion] \
[--header] [--types] [--utils] \
[--case] [--optional] [--removeUndefined]
```

- `--inFile`: Path to the `.proto` file to be parsed.
- `--outDir`: Directory to save the generated TypeScript files.
#### Options for codegen

| Option | Description | Default Value |
|---------------------|---------------------------------------------------------------------------------------------------------------------------|---------------|
| `--inFile` | Path to the `.proto` file to be parsed. | *Required* |
| `--outDir` | Directory to save the generated TypeScript files. | *Required* |
| `--enums` | Generate TypeScript enum types for PostgreSQL enums. | `false` |
| `--enumsJSON` | Generate JSON files mapping enum names to values. | `false` |
| `--typeUnion` | Generate TypeScript unions from enum types. | `false` |
| `--header` | Include a header in the generated TypeScript files to aid in integration. | `false` |
| `--types` | Generate TypeScript interfaces for protobuf messages. | `false` |
| `--utils` | Generate TypeScript utility functions for enums. | `false` |
| `--case` | Keep field casing as defined in the protobuf file. If false, fields will be converted to camelCase. | `false` |
| `--optional` | Generate TypeScript interfaces with optional fields. | `false` |
| `--removeUndefined` | Remove the 'UNDEFINED' enum entry if it exists. | `false` |
| `--help`, `-h` | Show this help message and exit. | |
| `--version`, `-v` | Show the version number and exit. | |

## Options
To explicitly set a boolean option to false, prepend the option with `--no-`. For example, to disable JSON enum mapping, use `--no-enumsJSON`.

```bash
pg-proto-parser --input <path-to-proto> \
--output <output-directory> \
[--enums] \
[--enumsJSON] \
[--typeUnion] \
[--header] \
[--types] \
[--utils] \
[--case] \
[--optional] \
[--removeUndefined]
```
### protogen

You can also generate code using the `protogen` command:

| Option | Description | Default Value |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------|---------------|
| `--input`, `-i` | Path to the `.proto` file to be parsed. | *Required* |
| `--output`, `-o` | Directory to save the generated TypeScript files. | *Required* |
| `--enums` | Generate TypeScript enum types for PostgreSQL enums. | `true` |
| `--enumsJSON` | Generate JSON files mapping enum names to integer values and vice versa. | `true` |
| `--typeUnion` | Generate TypeScript unions from enum types. | `true` |
| `--header` | Include a header in the generated TypeScript files to avoid manual manipulation which could cause issues in CI/CD pipelines. | `true` |
| `--types` | Generate TypeScript interfaces for protobuf messages. | `true` |
| `--utils` | Generate TypeScript utility functions for building ASTs. | `false` |
| `--case` | Keep field casing as defined in the protobuf file. If false, fields will be converted to camelCase. | `false` |
| `--optional` | Generate TypeScript interfaces with optional fields mapping to the PostgreSQL node types' fields; sets all fields to optional. | `true` |
| `--removeUndefined` | Remove the initial `UNDEFINED` enum entry and adjust the subsequent values by decrementing them. | `true` |
```bash
pg-proto-parser protogen --protoUrl <URL to proto file> \
--inFile <path to proto file> \
--outFile <path to output JS file> \
--originalPackageName <original package name> \
--newPackageName <new package name>
```

#### Options for protogen

To explicitly set a boolean option to false, prepend the option with `--no-`. For example, to disable JSON enum mapping, use `--no-enumsJSON`.
| Option | Description | Default Value |
|-------------------------|-------------------------------------------------------------------------------------|---------------|
| `--protoUrl` | Full URL to download the proto file (optional). | |
| `--inFile` | Path where the proto file will be saved or path to an existing proto file. | *Required* |
| `--outFile` | Path where the generated JavaScript file will be saved. | *Required* |
| `--originalPackageName` | Original package name to be replaced in the JS file. | protobufjs/minimal |
| `--newPackageName` | New package name to replace in the JS file. | @launchql/protobufjs/minimal |
| `--help`, `-h` | Show this help message. | |
| `--version`, `-v` | Show the version number. | |

Note: Boolean flags default to true when specified without a value. To set them to false, use the no- prefix (e.g., `--no-enumsJSON` will set `enumsJSON` to false).

## Related

Expand Down
8 changes: 6 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"main"
],
"bin": {
"pg-proto-parser": "main/parser.js"
"pg-proto-parser": "main/index.js"
},
"scripts": {
"build:main": "yarn tsc -p tsconfig.json --outDir main --module commonjs",
Expand All @@ -28,7 +28,7 @@
"prepare": "npm run clean && npm run build",
"lint": "eslint .",
"format": "eslint . --fix",
"dev": "NODE_ENV=development ts-node src/parser",
"dev": "ts-node src/index",
"test": "jest",
"test:watch": "jest --watch",
"test:debug": "node --inspect node_modules/.bin/jest --runInBand"
Expand Down Expand Up @@ -74,7 +74,11 @@
"typescript": "^5.0.4"
},
"dependencies": {
"@launchql/protobufjs": "7.2.6",
"@launchql/protobufjs-cli": "1.1.5",
"chalk": "^4.1.0",
"glob": "8.0.3",
"inquirerer": "1.9.0",
"minimist": "1.2.8",
"mkdirp": "3.0.1",
"nested-obj": "^0.0.1",
Expand Down
70 changes: 70 additions & 0 deletions packages/cli/src/commands/codegen/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { readAndParsePackageJson } from '../../package';
import { PgProtoParser, PgProtoParserOptions, getOptionsWithDefaults } from 'pg-proto-parser';
import o from 'nested-obj';

export const help = (): void => {
console.log(`
Usage:
pg-proto-parser codegen --inFile <path-to-proto> --outDir <output-directory>
[--enums] [--enumsJSON] [--typeUnion]
[--header] [--types] [--utils]
[--case] [--optional] [--removeUndefined]
Options:
--help, -h Show this help message and exit.
--inFile Path to the .proto file to be parsed.
--outDir Directory to save the generated TypeScript files.
--enums Generate TypeScript enum types for PostgreSQL enums.
--enumsJSON Generate JSON files mapping enum names to values.
--typeUnion Generate TypeScript unions from enum types.
--header Include a header in the generated TypeScript files.
--types Generate TypeScript interfaces for protobuf messages.
--utils Generate TypeScript utility functions for enums.
--case Keep field casing as defined in the protobuf file.
--optional Generate TypeScript interfaces with optional fields.
--removeUndefined Remove the 'UNDEFINED' enum entry if it exists.
--version, -v Show the version number and exit.
`);
}

export default async (argv) => {

if (argv.help || argv.h) {
help();
process.exit(0);
}

if (argv.version || argv.v) {
console.log(`Version: ${readAndParsePackageJson().version}`);
process.exit(0);
}

if (!argv.inFile || !argv.outDir) {
console.log('Input Error: inFile and outDir are required!');
help();
process.exit(1);
}

const options: PgProtoParserOptions = getOptionsWithDefaults({
outDir: argv.outDir
});

// Setting nested options using objectPath
o.set(options, 'enums.enabled', argv.enums);
o.set(options, 'enums.enumsAsTypeUnion', argv.typeUnion);
o.set(options, 'enums.json.enabled', argv.enumsJSON);
o.set(options, 'enums.removeUndefinedAt0', argv.removeUndefined);
o.set(options, 'includeHeader', argv.header);
o.set(options, 'parser.keepCase', argv.case);
o.set(options, 'types.enabled', argv.types);
o.set(options, 'types.optionalFields', argv.optional);
o.set(options, 'utils.astHelpers.enabled', argv.utils);

const parser = new PgProtoParser(argv.inFile, options);
// Generate TypeScript and JSON files
await parser.write();

return argv;
};
90 changes: 90 additions & 0 deletions packages/cli/src/commands/codegen/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { CLIOptions, Inquirerer } from 'inquirerer'
import { ParsedArgs } from 'minimist';
import cli, { help } from './cli';
export const commands = async (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => {

if (argv.help || argv.h) {
help();
process.exit(0);
}

argv = await prompter.prompt(argv, [
{
type: 'text',
name: 'inFile',
message: 'provide inFile (./path/to/proto.proto):'
},
{
type: 'text',
name: 'outDir',
message: 'provide outDir (./outputDir):'
},
{
type: 'confirm',
name: 'enums',
message: 'Enable enums?',
default: false,
useDefault: true
},
{
type: 'confirm',
name: 'typeUnion',
message: 'Use enums as type union?',
default: false,
useDefault: true
},
{
type: 'confirm',
name: 'enumsJSON',
message: 'Enable JSON for enums?',
default: false,
useDefault: true
},
{
type: 'confirm',
name: 'removeUndefined',
message: 'Remove undefined at index 0?',
default: false,
useDefault: true
},
{
type: 'confirm',
name: 'header',
message: 'Include header in output?',
default: false,
useDefault: true
},
{
type: 'confirm',
name: 'case',
message: 'Keep case in parser?',
default: false,
useDefault: true
},
{
type: 'confirm',
name: 'types',
message: 'Enable types?',
default: false,
useDefault: true
},
{
type: 'confirm',
name: 'optional',
message: 'Are optional fields enabled?',
default: false,
useDefault: true
},
{
type: 'confirm',
name: 'utils',
message: 'Enable AST helpers in utils?',
default: false,
useDefault: true
}
]);

argv = await cli(argv);

return argv;
};
64 changes: 64 additions & 0 deletions packages/cli/src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { CLIOptions, Inquirerer, Question } from 'inquirerer'
import { ParsedArgs } from 'minimist';

import { commands as codegen } from './codegen';
import { commands as protogen } from './protogen';

import { help as codegenHelp } from './codegen/cli';
import { help as protogenHelp } from './protogen/cli';

export const commands = async (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => {
let command;

if (argv._.length > 0) {
command = argv._.shift();
}

if (command) {
argv.command = command;
}

if (argv.help || argv.h) {
codegenHelp();
protogenHelp();
process.exit(0);
}


const questions: Question[] = [
{
type: 'autocomplete',
name: 'command',
message: 'choose a command',
options: [
'protogen',
'codegen'
]
}
];

({ command } = await prompter.prompt(argv, questions));

// recursive...
delete argv.command;

// @ts-ignore
prompter.exit = () => {};

switch (command) {
case 'protogen':
argv = await protogen(argv, prompter, _options);
break;

case 'codegen':
argv = await codegen(argv, prompter, _options);
break;

default:
console.log(`No recognized command provided or no command given: ${command}`);
break;
}

return argv;

};

0 comments on commit 4cac67b

Please sign in to comment.