@forwardimpact/libcodegen
Advanced tools
+63
-53
| #!/usr/bin/env node | ||
| import fs from "node:fs"; | ||
| import fs, { readFileSync } from "node:fs"; | ||
| import fsAsync from "node:fs/promises"; | ||
| import path from "node:path"; | ||
| import { execFileSync } from "node:child_process"; | ||
| import { parseArgs } from "node:util"; | ||
@@ -12,2 +11,3 @@ import protoLoader from "@grpc/proto-loader"; | ||
| import { createCli, SummaryRenderer } from "@forwardimpact/libcli"; | ||
| import { Finder } from "@forwardimpact/libutil"; | ||
@@ -23,2 +23,35 @@ import { Logger } from "@forwardimpact/libtelemetry"; | ||
| const { version: VERSION } = JSON.parse( | ||
| readFileSync(new URL("../package.json", import.meta.url), "utf8"), | ||
| ); | ||
| const definition = { | ||
| name: "fit-codegen", | ||
| version: VERSION, | ||
| description: "Generate protobuf types, service clients, and definitions", | ||
| options: { | ||
| all: { type: "boolean", description: "Generate all code" }, | ||
| type: { type: "boolean", description: "Generate protobuf types only" }, | ||
| service: { | ||
| type: "boolean", | ||
| description: "Generate service bases only", | ||
| }, | ||
| client: { type: "boolean", description: "Generate clients only" }, | ||
| definition: { | ||
| type: "boolean", | ||
| description: "Generate service definitions only", | ||
| }, | ||
| help: { type: "boolean", short: "h", description: "Show this help" }, | ||
| version: { type: "boolean", description: "Show version" }, | ||
| json: { type: "boolean", description: "Output help as JSON" }, | ||
| }, | ||
| examples: [ | ||
| "npx fit-codegen --all", | ||
| "npx fit-codegen --type", | ||
| "npx fit-codegen --service", | ||
| ], | ||
| }; | ||
| const cli = createCli(definition); | ||
| /** | ||
@@ -58,47 +91,12 @@ * Create tar.gz bundle of all directories inside sourcePath | ||
| /** | ||
| * Print CLI usage help | ||
| */ | ||
| function printUsage() { | ||
| process.stdout.write( | ||
| [ | ||
| "Usage:", | ||
| ` npx fit-codegen --all # Generate all code`, | ||
| ` npx fit-codegen --type # Generate protobuf types only`, | ||
| ` npx fit-codegen --service # Generate service bases only`, | ||
| ` npx fit-codegen --client # Generate clients only`, | ||
| ` npx fit-codegen --definition # Generate service definitions only`, | ||
| ].join("\n") + "\n", | ||
| ); | ||
| } | ||
| /** | ||
| * Parse command line flags | ||
| * Parse command line flags using libcli | ||
| * @returns {object} Parsed flags with convenience methods | ||
| */ | ||
| function parseFlags() { | ||
| const { values } = parseArgs({ | ||
| options: { | ||
| all: { | ||
| type: "boolean", | ||
| default: false, | ||
| }, | ||
| type: { | ||
| type: "boolean", | ||
| default: false, | ||
| }, | ||
| service: { | ||
| type: "boolean", | ||
| default: false, | ||
| }, | ||
| client: { | ||
| type: "boolean", | ||
| default: false, | ||
| }, | ||
| definition: { | ||
| type: "boolean", | ||
| default: false, | ||
| }, | ||
| }, | ||
| }); | ||
| const parsed = cli.parse(process.argv.slice(2)); | ||
| if (!parsed) { | ||
| process.exit(0); | ||
| } | ||
| const { values } = parsed; | ||
| const doAll = values.all; | ||
@@ -211,3 +209,2 @@ return { | ||
| const relPath = path.relative(process.cwd(), sourcePath); | ||
| const lines = [`Generated ${totalFiles} files in ./${relPath}/`]; | ||
@@ -221,2 +218,3 @@ const dirLabels = { | ||
| const items = []; | ||
| if (fs.existsSync(sourcePath)) { | ||
@@ -229,6 +227,15 @@ const dirs = fs | ||
| const label = dirLabels[dir.name]; | ||
| if (label) lines.push(` ${dir.name}/ — ${label}`); | ||
| if (label) items.push({ label: `${dir.name}/`, description: label }); | ||
| } | ||
| } | ||
| const summary = new SummaryRenderer({ process }); | ||
| summary.render( | ||
| { | ||
| title: `Generated ${totalFiles} files in ./${relPath}/`, | ||
| items, | ||
| }, | ||
| process.stdout, | ||
| ); | ||
| const generated = [ | ||
@@ -240,5 +247,5 @@ flags.doTypes && "types", | ||
| ].filter(Boolean); | ||
| lines.push(`\nCode generation complete (${generated.join(", ")}).`); | ||
| process.stdout.write(lines.join("\n") + "\n"); | ||
| process.stdout.write( | ||
| `\nCode generation complete (${generated.join(", ")}).\n`, | ||
| ); | ||
| } | ||
@@ -296,5 +303,6 @@ | ||
| if (!parsedFlags.hasGenerationFlags()) { | ||
| printUsage(); | ||
| process.exitCode = 1; | ||
| return; | ||
| cli.usageError( | ||
| "no generation flags specified (use --all, --type, --service, --client, or --definition)", | ||
| ); | ||
| process.exit(2); | ||
| } | ||
@@ -353,3 +361,5 @@ | ||
| } catch (err) { | ||
| process.stderr.write(`Error: ${err.message}\n`); | ||
| const logger = new Logger("codegen"); | ||
| logger.exception("main", err); | ||
| cli.error(err.message); | ||
| process.exit(1); | ||
@@ -360,4 +370,4 @@ } | ||
| main().catch((err) => { | ||
| process.stderr.write(`Unexpected error: ${err.message}\n`); | ||
| cli.error(err.message); | ||
| process.exit(1); | ||
| }); |
+3
-2
| { | ||
| "name": "@forwardimpact/libcodegen", | ||
| "version": "0.1.39", | ||
| "version": "0.1.41", | ||
| "description": "Protocol Buffer code generation utilities for Guide", | ||
@@ -20,2 +20,3 @@ "license": "Apache-2.0", | ||
| "dependencies": { | ||
| "@forwardimpact/libcli": "^0.1.0", | ||
| "@forwardimpact/libstorage": "^0.1.53", | ||
@@ -27,3 +28,3 @@ "@forwardimpact/libtelemetry": "^0.1.22", | ||
| "protobufjs": "^7.5.4", | ||
| "protobufjs-cli": "^2.0.0" | ||
| "protobufjs-cli": "^2.0.1" | ||
| }, | ||
@@ -30,0 +31,0 @@ "devDependencies": { |
50795
0.93%869
0.93%8
14.29%+ Added
Updated