UNPKG

@sil/args

Version:
181 lines (145 loc) 4.48 kB
import fs from "fs"; import path from "path"; import { camelCase } from "@sil/case"; import { ArgValue, ArgType } from "./types"; export const fixArg = (input: ArgValue): ArgValue => { let value: ArgValue = input; if (typeof input == "string") { if (input == "false") value = false as boolean; if (input == "true") value = true as boolean; if (parseFloat(input) > -999) value = parseFloat(input) as number; if (input.endsWith(',')) value = input.slice(0, -1); } return value; }; export const parseArguments = (inputs: string[]): ArgType => { const args = {}; let lastKey = ""; inputs.forEach((input) => { if (input.indexOf("--") == 0) { const key = input.replace("--", ""); lastKey = camelCase(key); args[lastKey] = []; } else if (Object.keys(args).length > 0) { args[lastKey].push(fixArg(input)); } }); Object.keys(args).map((key) => { if (args[key].length == 0) { args[key] = true; } if (args[key].length == 1) { args[key] = args[key][0]; } }); return args; }; interface argOptions { allowedKeys: string[]; removeKeys: string[]; type: { [key in string]: 'string' | 'number' | 'array' | 'boolean' } } interface Arguments { [key: string]: any; } const defaultArgOptions: argOptions = { allowedKeys: [], removeKeys: [], type: {} } const processAllowedKeys = (args: Arguments, options: argOptions): Arguments => { const newArgs = { ...args }; Object.keys(newArgs).forEach((key) => { if (!options.allowedKeys.includes(key)) { delete newArgs[key]; } }); return newArgs; } const processRemoveKeys = (args: Arguments, options: argOptions): Arguments => { const newArgs = { ...args }; options.removeKeys.forEach((key) => { delete newArgs[key]; }); return newArgs; } const processTypedKeys = (args: Arguments, options: argOptions): Arguments => { const newArgs = { ...args }; Object.keys(args).forEach((key) => { if (options.type[key] == 'number') { if (typeof newArgs[key] == 'boolean') { newArgs[key] = newArgs[key] ? 1 : 0; } else { newArgs[key] = parseFloat(newArgs[key] as string); } } else if (options.type[key] == 'array') { if (typeof newArgs[key] !== 'object') { if (typeof newArgs[key] == 'string') { newArgs[key] = [(newArgs[key] as string).split(',')].flat(); } else { newArgs[key] = [newArgs[key]].flat(); } } } else if (options.type[key] == 'boolean') { if (typeof newArgs[key] == 'string') { newArgs[key] = newArgs[key] == 'true'; } if (typeof newArgs[key] == 'number') { if (newArgs[key] > 0) { newArgs[key] = true; } else { newArgs[key] = false; } } newArgs[key] = Boolean(newArgs[key]) } else if (options.type[key] == 'string') { newArgs[key] = newArgs[key].toString(); } else { newArgs[key] = newArgs[key]; } }); return newArgs; } export const processFiles = (args: Arguments, options?: argOptions): Arguments => { const allowedDataFiles = ['html','txt','md','json','xml','js','ts','css','scss','sass','less','csv']; const files = Object.keys(args).reduce((acc, key) => { if (typeof args[key] == 'string' && args[key].includes('.') && allowedDataFiles.includes(args[key].split('.').pop() as string)) { acc[key] = args[key]; } return acc; }, {} as { [key: string]: string }); const newArgs = { ...args }; Object.keys(files).forEach((key) => { const file = files[key]; const filePath = path.join(process.cwd(), file); if (fs.existsSync(filePath)) { newArgs[`${key}Data`] = JSON.parse(fs.readFileSync(filePath, 'utf8')); } else { throw new Error(`File ${filePath} does not exist`); } } ); return newArgs; } export const getArgs = (args: Partial<argOptions> = {}): ArgType => { const options = { ...defaultArgOptions, ...args }; let processedArgs = parseArguments(process.argv); if (options.allowedKeys.length) { processedArgs = processAllowedKeys(processedArgs, options); } if (options.removeKeys.length) { processedArgs = processRemoveKeys(processedArgs, options); } if (Object.keys(options.type).length) { processedArgs = processTypedKeys(processedArgs, options); } processedArgs = processFiles(processedArgs, options) return processedArgs; };