Created
October 22, 2024 04:12
-
-
Save timepp/605f9d15818dad3242e2bbd703676b1c to your computer and use it in GitHub Desktop.
A pattern to handle command line arguments + config file uniformly, in a type-safe way
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { parseArgs } from "jsr:@std/cli/parse-args" | |
// Define the option names, their default values, and (implicitly) their types, using a DRY (dont repeat yourself) way | |
// The option name itself will be used as the command line switch, and the keys in config json file | |
// This object is also used to enumerate all options | |
// Supported type: number, string, boolean, string array | |
const defaultConfig = { | |
area: 'Recording', | |
steps: ['ocv', 'classify', 'excel'] as 'ocv'|'classify'|'excel'[], | |
startDate: '', | |
endDate: '', | |
excel: '', | |
classifyBatchCount: 5, | |
browser: 'msedge', | |
browserProfile: '' | |
} | |
// Define the option descriptions and command line aliases | |
const configDescription: {[P in keyof typeof defaultConfig]:[/*doc*/string, /*alias*/string?]} = { | |
area: [`area name, one of ${ac.areaConf.map(v => v.name).join(',')}`], | |
steps: ['steps to execute'], | |
startDate: ['start date, e.g. 2024-10-22'], | |
endDate: ['end date, if omitted, only one day will be processed'], | |
excel: ['output excel file'], | |
classifyBatchCount: ['number of classify batch', 'n'], | |
browser: ['browser to use: either msedge or chrome'], | |
browserProfile: ['browser profile to use, if not specified, default profile will be used'] | |
} | |
// Derive config from the default config object | |
type RunConfig = typeof defaultConfig | |
function showHelp() { | |
console.log('Usage: deno run -A run.ts <OPTIONS>') | |
console.log() | |
console.log('Options:') | |
for (const k in configDescription) { | |
const kk = k as keyof typeof configDescription | |
const v = configDescription[kk] as [string, string] | |
const flag = v[1] ? ` (${v[1]})` : '' | |
const defaultValue = JSON.stringify(defaultConfig[kk]) | |
console.log(` - %c${kk}%c${flag} %c= ${defaultValue}:`, 'font-weight: bold; color: blue', 'color: blue', 'color: grey', v[0]) | |
} | |
console.log() | |
console.log('Steps: ocv, classify, excel') | |
console.log(' ocv: get ocv data') | |
console.log(' classify: classify ocv data using GPT') | |
console.log(' excel: update excel data') | |
console.log('if steps is not specified, all steps will be executed, otherwise only the specified steps will be executed.') | |
console.log() | |
console.log(' You can put the same options in run.json, so that you don\'t need to specify them in command line.') | |
} | |
function getConfigFromFile(path: string) { | |
try { | |
return JSON.parse(Deno.readTextFileSync(path)) as RunConfig | |
} catch (_e) { | |
return {} as RunConfig | |
} | |
} | |
async function main() { | |
const commandLineArgs = parseArgs(Deno.args, { | |
collect: Object.keys(defaultConfig).filter(v => Array.isArray(defaultConfig[v as keyof typeof defaultConfig])), | |
alias: Object.fromEntries(Object.entries(configDescription).map(v => [v[1][1], v[0]])) as { [k: string]: string }, | |
}) as unknown as typeof defaultConfig & { _: string[], help?: boolean } | |
// Handle --help | |
if (commandLineArgs.help) { | |
showHelp() | |
return | |
} | |
// Merge the default config, config file, commandline args, with the expected priority | |
const conf = {...defaultConfig, ...getConfigFromFile('run.json'), ...commandLineArgs} as RunConfig | |
// Use config in the remaining logic. | |
... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is the effect of "--help" for the code: