@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.
- package/CHANGELOG.md +64 -0
- package/LICENSE +21 -0
- package/README.md +268 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +268 -0
- package/dist/commands/deparse.d.ts +1 -0
- package/dist/commands/deparse.js +66 -0
- package/dist/commands/parse.d.ts +1 -0
- package/dist/commands/parse.js +60 -0
- package/dist/commands/proto-fetch/cli.d.ts +14 -0
- package/dist/commands/proto-fetch/cli.js +41 -0
- package/dist/commands/proto-fetch/helpers.d.ts +3 -0
- package/dist/commands/proto-fetch/helpers.js +73 -0
- package/dist/commands/proto-fetch.d.ts +1 -0
- package/dist/commands/proto-fetch.js +42 -0
- package/dist/commands/proto-gen.d.ts +1 -0
- package/dist/commands/proto-gen.js +59 -0
- package/dist/commands/runtime-schema.d.ts +1 -0
- package/dist/commands/runtime-schema.js +70 -0
- package/dist/esm/commands/deparse.js +60 -0
- package/dist/esm/commands/parse.js +54 -0
- package/dist/esm/commands/proto-fetch/cli.js +37 -0
- package/dist/esm/commands/proto-fetch/helpers.js +64 -0
- package/dist/esm/commands/proto-fetch.js +36 -0
- package/dist/esm/commands/proto-gen.js +53 -0
- package/dist/esm/commands/runtime-schema.js +64 -0
- package/dist/esm/index.js +56 -0
- package/dist/esm/package.js +26 -0
- package/dist/esm/utils/help.js +190 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +61 -0
- package/dist/package.d.ts +1 -0
- package/dist/package.js +29 -0
- package/dist/package.json +60 -0
- package/dist/utils/help.d.ts +2 -0
- package/dist/utils/help.js +197 -0
- package/jest.config.js +18 -0
- package/package.json +60 -0
- package/src/commands/deparse.ts +60 -0
- package/src/commands/parse.ts +60 -0
- package/src/commands/proto-fetch/cli.ts +52 -0
- package/src/commands/proto-fetch/helpers.ts +72 -0
- package/src/commands/proto-fetch.ts +42 -0
- package/src/commands/proto-gen.ts +49 -0
- package/src/commands/runtime-schema.ts +74 -0
- package/src/index.ts +69 -0
- package/src/package.ts +33 -0
- package/src/utils/help.ts +198 -0
- package/tsconfig.esm.json +9 -0
- 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
|
+
});
|