@pgsql/cli 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +21 -0
  3. package/README.md +268 -0
  4. package/dist/LICENSE +21 -0
  5. package/dist/README.md +268 -0
  6. package/dist/commands/deparse.d.ts +1 -0
  7. package/dist/commands/deparse.js +66 -0
  8. package/dist/commands/parse.d.ts +1 -0
  9. package/dist/commands/parse.js +60 -0
  10. package/dist/commands/proto-fetch/cli.d.ts +14 -0
  11. package/dist/commands/proto-fetch/cli.js +41 -0
  12. package/dist/commands/proto-fetch/helpers.d.ts +3 -0
  13. package/dist/commands/proto-fetch/helpers.js +73 -0
  14. package/dist/commands/proto-fetch.d.ts +1 -0
  15. package/dist/commands/proto-fetch.js +42 -0
  16. package/dist/commands/proto-gen.d.ts +1 -0
  17. package/dist/commands/proto-gen.js +59 -0
  18. package/dist/commands/runtime-schema.d.ts +1 -0
  19. package/dist/commands/runtime-schema.js +70 -0
  20. package/dist/esm/commands/deparse.js +60 -0
  21. package/dist/esm/commands/parse.js +54 -0
  22. package/dist/esm/commands/proto-fetch/cli.js +37 -0
  23. package/dist/esm/commands/proto-fetch/helpers.js +64 -0
  24. package/dist/esm/commands/proto-fetch.js +36 -0
  25. package/dist/esm/commands/proto-gen.js +53 -0
  26. package/dist/esm/commands/runtime-schema.js +64 -0
  27. package/dist/esm/index.js +56 -0
  28. package/dist/esm/package.js +26 -0
  29. package/dist/esm/utils/help.js +190 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +61 -0
  32. package/dist/package.d.ts +1 -0
  33. package/dist/package.js +29 -0
  34. package/dist/package.json +60 -0
  35. package/dist/utils/help.d.ts +2 -0
  36. package/dist/utils/help.js +197 -0
  37. package/jest.config.js +18 -0
  38. package/package.json +60 -0
  39. package/src/commands/deparse.ts +60 -0
  40. package/src/commands/parse.ts +60 -0
  41. package/src/commands/proto-fetch/cli.ts +52 -0
  42. package/src/commands/proto-fetch/helpers.ts +72 -0
  43. package/src/commands/proto-fetch.ts +42 -0
  44. package/src/commands/proto-gen.ts +49 -0
  45. package/src/commands/runtime-schema.ts +74 -0
  46. package/src/index.ts +69 -0
  47. package/src/package.ts +33 -0
  48. package/src/utils/help.ts +198 -0
  49. package/tsconfig.esm.json +9 -0
  50. package/tsconfig.json +9 -0
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deparseCommand = deparseCommand;
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ const pgsql_deparser_1 = require("pgsql-deparser");
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const help_1 = require("../utils/help");
12
+ async function deparseCommand(argv) {
13
+ if (argv.help) {
14
+ (0, help_1.showHelp)('deparse');
15
+ process.exit(0);
16
+ }
17
+ try {
18
+ let ast;
19
+ // Read AST from file or stdin
20
+ if (argv.input || argv.i) {
21
+ const inputFile = argv.input || argv.i;
22
+ const filePath = inputFile.startsWith('/')
23
+ ? inputFile
24
+ : (0, path_1.resolve)((0, path_1.join)(process.cwd(), inputFile));
25
+ const content = (0, fs_1.readFileSync)(filePath, 'utf-8');
26
+ ast = JSON.parse(content);
27
+ }
28
+ else if (!process.stdin.isTTY) {
29
+ // Read from stdin
30
+ const chunks = [];
31
+ for await (const chunk of process.stdin) {
32
+ chunks.push(chunk);
33
+ }
34
+ const content = Buffer.concat(chunks).toString();
35
+ ast = JSON.parse(content);
36
+ }
37
+ else {
38
+ console.error(chalk_1.default.red('Error: No input provided. Use -i <file> or pipe input via stdin'));
39
+ (0, help_1.showHelp)('deparse');
40
+ process.exit(1);
41
+ }
42
+ // Deparse AST to SQL
43
+ const sql = await (0, pgsql_deparser_1.deparse)(ast);
44
+ // Write output
45
+ if (argv.output || argv.o) {
46
+ const outputFile = argv.output || argv.o;
47
+ (0, fs_1.writeFileSync)(outputFile, sql);
48
+ console.log(chalk_1.default.green(`✓ SQL written to ${outputFile}`));
49
+ }
50
+ else {
51
+ process.stdout.write(sql);
52
+ }
53
+ }
54
+ catch (error) {
55
+ if (error.code === 'ENOENT') {
56
+ console.error(chalk_1.default.red(`Error: File not found: ${argv.input || argv.i}`));
57
+ }
58
+ else if (error instanceof SyntaxError) {
59
+ console.error(chalk_1.default.red('Error: Invalid JSON input'));
60
+ }
61
+ else {
62
+ console.error(chalk_1.default.red('Deparse error:'), error.message || error);
63
+ }
64
+ process.exit(1);
65
+ }
66
+ }
@@ -0,0 +1 @@
1
+ export declare function parseCommand(argv: any): Promise<void>;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseCommand = parseCommand;
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ const pgsql_parser_1 = require("pgsql-parser");
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const help_1 = require("../utils/help");
12
+ async function parseCommand(argv) {
13
+ if (argv.help) {
14
+ (0, help_1.showHelp)('parse');
15
+ process.exit(0);
16
+ }
17
+ const sqlFile = argv._[1];
18
+ if (!sqlFile) {
19
+ console.error(chalk_1.default.red('Error: SQL file required'));
20
+ (0, help_1.showHelp)('parse');
21
+ process.exit(1);
22
+ }
23
+ try {
24
+ // Resolve file path
25
+ const filePath = sqlFile.startsWith('/')
26
+ ? sqlFile
27
+ : (0, path_1.resolve)((0, path_1.join)(process.cwd(), sqlFile));
28
+ // Read SQL content
29
+ const content = (0, fs_1.readFileSync)(filePath, 'utf-8');
30
+ // Parse SQL
31
+ const ast = await (0, pgsql_parser_1.parse)(content);
32
+ // Clean AST if requested
33
+ if (argv.clean) {
34
+ // For now, we'll skip the clean functionality until we can import it properly
35
+ console.warn(chalk_1.default.yellow('Warning: --clean flag is not yet implemented'));
36
+ }
37
+ // Format output
38
+ const format = argv.format || 'pretty';
39
+ const output = format === 'json'
40
+ ? JSON.stringify(ast)
41
+ : JSON.stringify(ast, null, 2);
42
+ // Write output
43
+ if (argv.output) {
44
+ (0, fs_1.writeFileSync)(argv.output, output);
45
+ console.log(chalk_1.default.green(`✓ AST written to ${argv.output}`));
46
+ }
47
+ else {
48
+ process.stdout.write(output);
49
+ }
50
+ }
51
+ catch (error) {
52
+ if (error.code === 'ENOENT') {
53
+ console.error(chalk_1.default.red(`Error: File not found: ${sqlFile}`));
54
+ }
55
+ else {
56
+ console.error(chalk_1.default.red('Parse error:'), error.message || error);
57
+ }
58
+ process.exit(1);
59
+ }
60
+ }
@@ -0,0 +1,14 @@
1
+ export interface CommandOptions {
2
+ help?: boolean;
3
+ h?: boolean;
4
+ version?: boolean;
5
+ v?: boolean;
6
+ protoUrl?: string;
7
+ inFile: string;
8
+ outFile: string;
9
+ originalPackageName: string;
10
+ newPackageName: string;
11
+ }
12
+ export declare const help: () => void;
13
+ declare const _default: (argv: CommandOptions) => Promise<CommandOptions>;
14
+ export default _default;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.help = void 0;
4
+ const helpers_1 = require("./helpers");
5
+ const help = () => {
6
+ console.log(`
7
+ Usage:
8
+
9
+ pg-proto-parser protogen --protoUrl <URL to proto file>
10
+ --inFile <path to proto file>
11
+ --outFile <path to output JS file>
12
+ --originalPackageName <original package name>
13
+ --newPackageName <new package name>
14
+
15
+ Options:
16
+
17
+ --help, -h Show this help message.
18
+ --version, -v Show the version number.
19
+ --protoUrl Full URL to download the proto file (optional).
20
+ --inFile Path where the proto file will be saved or path to an existing proto file.
21
+ --outFile Path where the generated JavaScript file will be saved.
22
+ --originalPackageName Original package name to be replaced in the JS file.
23
+ --newPackageName New package name to replace in the JS file.
24
+ `);
25
+ };
26
+ exports.help = help;
27
+ exports.default = async (argv) => {
28
+ try {
29
+ if (argv.protoUrl) {
30
+ await (0, helpers_1.downloadProtoFile)(argv.protoUrl, argv.inFile);
31
+ }
32
+ await (0, helpers_1.generateProtoJS)(argv.inFile, argv.outFile);
33
+ await (0, helpers_1.replaceTextInProtoJS)(argv.outFile, argv.originalPackageName, argv.newPackageName);
34
+ console.log('All operations completed successfully.');
35
+ }
36
+ catch (error) {
37
+ // @ts-ignore
38
+ console.error('An error occurred:', error.message);
39
+ }
40
+ return argv;
41
+ };
@@ -0,0 +1,3 @@
1
+ export declare const downloadProtoFile: (protoUrl: string, filePath: string) => Promise<void>;
2
+ export declare const generateProtoJS: (inFile: string, outFile: string) => Promise<void>;
3
+ export declare const replaceTextInProtoJS: (filePath: string, originalPackage: string, newPackage: string) => Promise<void>;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.replaceTextInProtoJS = exports.generateProtoJS = exports.downloadProtoFile = void 0;
7
+ const https_1 = __importDefault(require("https"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const child_process_1 = require("child_process");
10
+ const mkdirp_1 = require("mkdirp");
11
+ const path_1 = require("path");
12
+ // Download .proto file if URL
13
+ const downloadProtoFile = (protoUrl, filePath) => {
14
+ (0, mkdirp_1.sync)((0, path_1.dirname)(filePath));
15
+ return new Promise((resolve, reject) => {
16
+ https_1.default.get(protoUrl, (response) => {
17
+ if (response.statusCode !== 200) {
18
+ console.error(`Failed to download file: Status Code: ${response.statusCode}`);
19
+ response.resume(); // consume response data to free up memory
20
+ reject(new Error('Failed to download file'));
21
+ return;
22
+ }
23
+ const fileStream = fs_1.default.createWriteStream(filePath);
24
+ response.pipe(fileStream);
25
+ fileStream.on('finish', () => {
26
+ fileStream.close();
27
+ console.log('Downloaded proto file.');
28
+ resolve();
29
+ });
30
+ }).on('error', (err) => {
31
+ console.error(`Error downloading the file: ${err.message}`);
32
+ fs_1.default.unlink(filePath, () => { }); // Delete the file async. (No need to check error here)
33
+ reject(err);
34
+ });
35
+ });
36
+ };
37
+ exports.downloadProtoFile = downloadProtoFile;
38
+ // Generate JavaScript from proto file using pbjs
39
+ const generateProtoJS = (inFile, outFile) => new Promise((resolve, reject) => {
40
+ const command = `pbjs --keep-case -t static-module -o ${outFile} ${inFile}`;
41
+ (0, mkdirp_1.sync)((0, path_1.dirname)(outFile));
42
+ (0, child_process_1.exec)(command, (error, _stdout, _stderr) => {
43
+ if (error) {
44
+ console.error(`Error during code generation: ${error.message}`);
45
+ reject(error);
46
+ return;
47
+ }
48
+ console.log('Generated proto.js from proto file.');
49
+ resolve();
50
+ });
51
+ });
52
+ exports.generateProtoJS = generateProtoJS;
53
+ // Replace text in generated JS file
54
+ const replaceTextInProtoJS = (filePath, originalPackage, newPackage) => new Promise((resolve, reject) => {
55
+ fs_1.default.readFile(filePath, 'utf8', (err, data) => {
56
+ if (err) {
57
+ console.error(`Error reading proto.js: ${err.message}`);
58
+ reject(err);
59
+ return;
60
+ }
61
+ const result = data.replace(new RegExp(originalPackage, 'g'), newPackage);
62
+ fs_1.default.writeFile(filePath, result, 'utf8', (err) => {
63
+ if (err) {
64
+ console.error(`Error writing back to proto.js: ${err.message}`);
65
+ reject(err);
66
+ return;
67
+ }
68
+ console.log('Replaced text in proto.js successfully.');
69
+ resolve();
70
+ });
71
+ });
72
+ });
73
+ exports.replaceTextInProtoJS = replaceTextInProtoJS;
@@ -0,0 +1 @@
1
+ export declare function protoFetchCommand(argv: any): Promise<void>;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.protoFetchCommand = protoFetchCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const help_1 = require("../utils/help");
9
+ const helpers_1 = require("./proto-fetch/helpers");
10
+ async function protoFetchCommand(argv) {
11
+ if (argv.help) {
12
+ (0, help_1.showHelp)('proto-fetch');
13
+ process.exit(0);
14
+ }
15
+ const url = argv.url;
16
+ const inFile = argv.inFile;
17
+ const outFile = argv.outFile;
18
+ const replacePkg = argv['replace-pkg'] || 'protobufjs/minimal';
19
+ const withPkg = argv['with-pkg'] || '@launchql/protobufjs/minimal';
20
+ if (!inFile || !outFile) {
21
+ console.error(chalk_1.default.red('Error: --inFile and --outFile are required'));
22
+ (0, help_1.showHelp)('proto-fetch');
23
+ process.exit(1);
24
+ }
25
+ try {
26
+ if (url) {
27
+ console.log(chalk_1.default.blue(`Downloading proto file from ${url}...`));
28
+ await (0, helpers_1.downloadProtoFile)(url, inFile);
29
+ console.log(chalk_1.default.green(`✓ Proto file saved to ${inFile}`));
30
+ }
31
+ console.log(chalk_1.default.blue('Generating JavaScript from proto file...'));
32
+ await (0, helpers_1.generateProtoJS)(inFile, outFile);
33
+ console.log(chalk_1.default.blue(`Replacing package references...`));
34
+ await (0, helpers_1.replaceTextInProtoJS)(outFile, replacePkg, withPkg);
35
+ console.log(chalk_1.default.green(`✓ All operations completed successfully`));
36
+ console.log(chalk_1.default.green(`✓ Generated file: ${outFile}`));
37
+ }
38
+ catch (error) {
39
+ console.error(chalk_1.default.red('Proto fetch error:'), error.message || error);
40
+ process.exit(1);
41
+ }
42
+ }
@@ -0,0 +1 @@
1
+ export declare function protoGenCommand(argv: any): Promise<void>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.protoGenCommand = protoGenCommand;
7
+ const pg_proto_parser_1 = require("pg-proto-parser");
8
+ const nested_obj_1 = __importDefault(require("nested-obj"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const help_1 = require("../utils/help");
11
+ async function protoGenCommand(argv) {
12
+ if (argv.help) {
13
+ (0, help_1.showHelp)('proto-gen');
14
+ process.exit(0);
15
+ }
16
+ if (!argv.inFile || !argv.outDir) {
17
+ console.error(chalk_1.default.red('Error: --inFile and --outDir are required'));
18
+ (0, help_1.showHelp)('proto-gen');
19
+ process.exit(1);
20
+ }
21
+ try {
22
+ const options = (0, pg_proto_parser_1.getOptionsWithDefaults)({
23
+ outDir: argv.outDir
24
+ });
25
+ // Set options based on flags
26
+ if (argv.enums)
27
+ nested_obj_1.default.set(options, 'enums.enabled', true);
28
+ if (argv['enums-json'])
29
+ nested_obj_1.default.set(options, 'enums.json.enabled', true);
30
+ if (argv.types)
31
+ nested_obj_1.default.set(options, 'types.enabled', true);
32
+ if (argv.utils)
33
+ nested_obj_1.default.set(options, 'utils.enums.enabled', true);
34
+ if (argv['ast-helpers'])
35
+ nested_obj_1.default.set(options, 'utils.astHelpers.enabled', true);
36
+ if (argv['wrapped-helpers'])
37
+ nested_obj_1.default.set(options, 'utils.wrappedAstHelpers.enabled', true);
38
+ if (argv.optional)
39
+ nested_obj_1.default.set(options, 'types.optionalFields', true);
40
+ if (argv['keep-case'])
41
+ nested_obj_1.default.set(options, 'parser.keepCase', true);
42
+ if (argv['remove-undefined'])
43
+ nested_obj_1.default.set(options, 'enums.removeUndefinedAt0', true);
44
+ // Additional options that might be useful
45
+ if (argv['type-union'])
46
+ nested_obj_1.default.set(options, 'enums.enumsAsTypeUnion', true);
47
+ if (argv.header)
48
+ nested_obj_1.default.set(options, 'includeHeader', true);
49
+ console.log(chalk_1.default.blue('Parsing protobuf file...'));
50
+ const parser = new pg_proto_parser_1.PgProtoParser(argv.inFile, options);
51
+ console.log(chalk_1.default.blue('Generating TypeScript files...'));
52
+ await parser.write();
53
+ console.log(chalk_1.default.green(`✓ Files generated in ${argv.outDir}`));
54
+ }
55
+ catch (error) {
56
+ console.error(chalk_1.default.red('Proto generation error:'), error.message || error);
57
+ process.exit(1);
58
+ }
59
+ }
@@ -0,0 +1 @@
1
+ export declare function runtimeSchemaCommand(argv: any): Promise<void>;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runtimeSchemaCommand = runtimeSchemaCommand;
7
+ const pg_proto_parser_1 = require("pg-proto-parser");
8
+ const fs_1 = require("fs");
9
+ const path_1 = require("path");
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const help_1 = require("../utils/help");
12
+ async function runtimeSchemaCommand(argv) {
13
+ if (argv.help) {
14
+ (0, help_1.showHelp)('runtime-schema');
15
+ process.exit(0);
16
+ }
17
+ if (!argv.inFile || !argv.outDir) {
18
+ console.error(chalk_1.default.red('Error: --inFile and --outDir are required'));
19
+ (0, help_1.showHelp)('runtime-schema');
20
+ process.exit(1);
21
+ }
22
+ const format = argv.format || 'json';
23
+ const filename = argv.filename || 'runtime-schema';
24
+ try {
25
+ console.log(chalk_1.default.blue('Parsing protobuf file...'));
26
+ const options = (0, pg_proto_parser_1.getOptionsWithDefaults)({
27
+ outDir: argv.outDir
28
+ });
29
+ const parser = new pg_proto_parser_1.PgProtoParser(argv.inFile, options);
30
+ // Generate runtime schema
31
+ console.log(chalk_1.default.blue(`Generating runtime schema in ${format} format...`));
32
+ console.log(chalk_1.default.yellow('Warning: Runtime schema generation is not yet fully implemented'));
33
+ // Generate placeholder schema based on format
34
+ let content;
35
+ let fileExt;
36
+ if (format === 'typescript') {
37
+ // Generate TypeScript runtime schema placeholder
38
+ content = `// Runtime schema for PostgreSQL AST nodes
39
+ // Generated from: ${argv.inFile}
40
+
41
+ export interface RuntimeSchema {
42
+ // TODO: Implement runtime schema generation
43
+ nodes: Record<string, any>;
44
+ }
45
+
46
+ export const runtimeSchema: RuntimeSchema = {
47
+ nodes: {}
48
+ };
49
+ `;
50
+ fileExt = '.ts';
51
+ }
52
+ else {
53
+ // Generate JSON runtime schema placeholder
54
+ content = JSON.stringify({
55
+ generated: new Date().toISOString(),
56
+ source: argv.inFile,
57
+ nodes: {}
58
+ }, null, 2);
59
+ fileExt = '.json';
60
+ }
61
+ // Write file
62
+ const outputPath = (0, path_1.join)(argv.outDir, `${filename}${fileExt}`);
63
+ (0, fs_1.writeFileSync)(outputPath, content);
64
+ console.log(chalk_1.default.green(`✓ Runtime schema generated: ${outputPath}`));
65
+ }
66
+ catch (error) {
67
+ console.error(chalk_1.default.red('Runtime schema error:'), error.message || error);
68
+ process.exit(1);
69
+ }
70
+ }
@@ -0,0 +1,60 @@
1
+ import { readFileSync, writeFileSync } from 'fs';
2
+ import { resolve, join } from 'path';
3
+ import { deparse } from 'pgsql-deparser';
4
+ import chalk from 'chalk';
5
+ import { showHelp } from '../utils/help';
6
+ export async function deparseCommand(argv) {
7
+ if (argv.help) {
8
+ showHelp('deparse');
9
+ process.exit(0);
10
+ }
11
+ try {
12
+ let ast;
13
+ // Read AST from file or stdin
14
+ if (argv.input || argv.i) {
15
+ const inputFile = argv.input || argv.i;
16
+ const filePath = inputFile.startsWith('/')
17
+ ? inputFile
18
+ : resolve(join(process.cwd(), inputFile));
19
+ const content = readFileSync(filePath, 'utf-8');
20
+ ast = JSON.parse(content);
21
+ }
22
+ else if (!process.stdin.isTTY) {
23
+ // Read from stdin
24
+ const chunks = [];
25
+ for await (const chunk of process.stdin) {
26
+ chunks.push(chunk);
27
+ }
28
+ const content = Buffer.concat(chunks).toString();
29
+ ast = JSON.parse(content);
30
+ }
31
+ else {
32
+ console.error(chalk.red('Error: No input provided. Use -i <file> or pipe input via stdin'));
33
+ showHelp('deparse');
34
+ process.exit(1);
35
+ }
36
+ // Deparse AST to SQL
37
+ const sql = await deparse(ast);
38
+ // Write output
39
+ if (argv.output || argv.o) {
40
+ const outputFile = argv.output || argv.o;
41
+ writeFileSync(outputFile, sql);
42
+ console.log(chalk.green(`✓ SQL written to ${outputFile}`));
43
+ }
44
+ else {
45
+ process.stdout.write(sql);
46
+ }
47
+ }
48
+ catch (error) {
49
+ if (error.code === 'ENOENT') {
50
+ console.error(chalk.red(`Error: File not found: ${argv.input || argv.i}`));
51
+ }
52
+ else if (error instanceof SyntaxError) {
53
+ console.error(chalk.red('Error: Invalid JSON input'));
54
+ }
55
+ else {
56
+ console.error(chalk.red('Deparse error:'), error.message || error);
57
+ }
58
+ process.exit(1);
59
+ }
60
+ }
@@ -0,0 +1,54 @@
1
+ import { readFileSync, writeFileSync } from 'fs';
2
+ import { resolve, join } from 'path';
3
+ import { parse } from 'pgsql-parser';
4
+ import chalk from 'chalk';
5
+ import { showHelp } from '../utils/help';
6
+ export async function parseCommand(argv) {
7
+ if (argv.help) {
8
+ showHelp('parse');
9
+ process.exit(0);
10
+ }
11
+ const sqlFile = argv._[1];
12
+ if (!sqlFile) {
13
+ console.error(chalk.red('Error: SQL file required'));
14
+ showHelp('parse');
15
+ process.exit(1);
16
+ }
17
+ try {
18
+ // Resolve file path
19
+ const filePath = sqlFile.startsWith('/')
20
+ ? sqlFile
21
+ : resolve(join(process.cwd(), sqlFile));
22
+ // Read SQL content
23
+ const content = readFileSync(filePath, 'utf-8');
24
+ // Parse SQL
25
+ const ast = await parse(content);
26
+ // Clean AST if requested
27
+ if (argv.clean) {
28
+ // For now, we'll skip the clean functionality until we can import it properly
29
+ console.warn(chalk.yellow('Warning: --clean flag is not yet implemented'));
30
+ }
31
+ // Format output
32
+ const format = argv.format || 'pretty';
33
+ const output = format === 'json'
34
+ ? JSON.stringify(ast)
35
+ : JSON.stringify(ast, null, 2);
36
+ // Write output
37
+ if (argv.output) {
38
+ writeFileSync(argv.output, output);
39
+ console.log(chalk.green(`✓ AST written to ${argv.output}`));
40
+ }
41
+ else {
42
+ process.stdout.write(output);
43
+ }
44
+ }
45
+ catch (error) {
46
+ if (error.code === 'ENOENT') {
47
+ console.error(chalk.red(`Error: File not found: ${sqlFile}`));
48
+ }
49
+ else {
50
+ console.error(chalk.red('Parse error:'), error.message || error);
51
+ }
52
+ process.exit(1);
53
+ }
54
+ }
@@ -0,0 +1,37 @@
1
+ import { downloadProtoFile, generateProtoJS, replaceTextInProtoJS } from './helpers';
2
+ export const help = () => {
3
+ console.log(`
4
+ Usage:
5
+
6
+ pg-proto-parser protogen --protoUrl <URL to proto file>
7
+ --inFile <path to proto file>
8
+ --outFile <path to output JS file>
9
+ --originalPackageName <original package name>
10
+ --newPackageName <new package name>
11
+
12
+ Options:
13
+
14
+ --help, -h Show this help message.
15
+ --version, -v Show the version number.
16
+ --protoUrl Full URL to download the proto file (optional).
17
+ --inFile Path where the proto file will be saved or path to an existing proto file.
18
+ --outFile Path where the generated JavaScript file will be saved.
19
+ --originalPackageName Original package name to be replaced in the JS file.
20
+ --newPackageName New package name to replace in the JS file.
21
+ `);
22
+ };
23
+ export default async (argv) => {
24
+ try {
25
+ if (argv.protoUrl) {
26
+ await downloadProtoFile(argv.protoUrl, argv.inFile);
27
+ }
28
+ await generateProtoJS(argv.inFile, argv.outFile);
29
+ await replaceTextInProtoJS(argv.outFile, argv.originalPackageName, argv.newPackageName);
30
+ console.log('All operations completed successfully.');
31
+ }
32
+ catch (error) {
33
+ // @ts-ignore
34
+ console.error('An error occurred:', error.message);
35
+ }
36
+ return argv;
37
+ };
@@ -0,0 +1,64 @@
1
+ import https from 'https';
2
+ import fs from 'fs';
3
+ import { exec } from 'child_process';
4
+ import { sync as mkdirp } from 'mkdirp';
5
+ import { dirname } from 'path';
6
+ // Download .proto file if URL
7
+ export const downloadProtoFile = (protoUrl, filePath) => {
8
+ mkdirp(dirname(filePath));
9
+ return new Promise((resolve, reject) => {
10
+ https.get(protoUrl, (response) => {
11
+ if (response.statusCode !== 200) {
12
+ console.error(`Failed to download file: Status Code: ${response.statusCode}`);
13
+ response.resume(); // consume response data to free up memory
14
+ reject(new Error('Failed to download file'));
15
+ return;
16
+ }
17
+ const fileStream = fs.createWriteStream(filePath);
18
+ response.pipe(fileStream);
19
+ fileStream.on('finish', () => {
20
+ fileStream.close();
21
+ console.log('Downloaded proto file.');
22
+ resolve();
23
+ });
24
+ }).on('error', (err) => {
25
+ console.error(`Error downloading the file: ${err.message}`);
26
+ fs.unlink(filePath, () => { }); // Delete the file async. (No need to check error here)
27
+ reject(err);
28
+ });
29
+ });
30
+ };
31
+ // Generate JavaScript from proto file using pbjs
32
+ export const generateProtoJS = (inFile, outFile) => new Promise((resolve, reject) => {
33
+ const command = `pbjs --keep-case -t static-module -o ${outFile} ${inFile}`;
34
+ mkdirp(dirname(outFile));
35
+ exec(command, (error, _stdout, _stderr) => {
36
+ if (error) {
37
+ console.error(`Error during code generation: ${error.message}`);
38
+ reject(error);
39
+ return;
40
+ }
41
+ console.log('Generated proto.js from proto file.');
42
+ resolve();
43
+ });
44
+ });
45
+ // Replace text in generated JS file
46
+ export const replaceTextInProtoJS = (filePath, originalPackage, newPackage) => new Promise((resolve, reject) => {
47
+ fs.readFile(filePath, 'utf8', (err, data) => {
48
+ if (err) {
49
+ console.error(`Error reading proto.js: ${err.message}`);
50
+ reject(err);
51
+ return;
52
+ }
53
+ const result = data.replace(new RegExp(originalPackage, 'g'), newPackage);
54
+ fs.writeFile(filePath, result, 'utf8', (err) => {
55
+ if (err) {
56
+ console.error(`Error writing back to proto.js: ${err.message}`);
57
+ reject(err);
58
+ return;
59
+ }
60
+ console.log('Replaced text in proto.js successfully.');
61
+ resolve();
62
+ });
63
+ });
64
+ });