#!/usr/bin/env -S node --experimental-strip-types --experimental-detect-module --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --disable-warning=ExperimentalWarning var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // src/evaluate/index.ts var import_node_util3 = require("util"); // src/evaluate/dep-check.ts var import_which = __toESM(require("which"), 1); async function depCheck(dependencies) { const cmd = this; for (const dep of dependencies) { try { await (0, import_which.default)(dep); } catch (e) { throw new Error(`"${dep}" is not installed. Please install it and try again.`); } } } // src/evaluate/stdin-async.ts async function stdinAsync(customStdin = process.stdin) { return new Promise((resolve, reject) => { if (customStdin.isTTY) { resolve(null); return; } let dataReceived = false; let input = ""; customStdin.setEncoding("utf8"); const onData = (chunk) => { dataReceived = true; input += chunk; }; const onEndOrClose = () => { cleanup(); resolve(input.trim() || null); }; const onError = (err) => { cleanup(); reject(err); }; const cleanup = () => { customStdin.removeListener("data", onData); customStdin.removeListener("end", onEndOrClose); customStdin.removeListener("close", onEndOrClose); customStdin.removeListener("error", onError); clearTimeout(timeout); }; customStdin.on("data", onData); customStdin.on("end", onEndOrClose); customStdin.on("close", onEndOrClose); customStdin.on("error", onError); const timeout = setTimeout(() => { if (!dataReceived) { cleanup(); resolve(null); } }, 1e3); }); } // src/evaluate/stdin-loop.ts function validateStdinType(type) { const validOptions = ["loop", "loopJson", "loopLines", true, false, void 0]; return validOptions.includes(type); } var stdinLoop = async (type, stdinAsync2) => { if (!validateStdinType(type)) { throw new Error(`Invalid stdin: ${type}`); } if (!type) return [null]; const stdin = await stdinAsync2(); if (!stdin) return [null]; if (type == "loop" || type == "loopJson") { try { const parsedJson = JSON.parse(stdin); if (parsedJson && Array.isArray(parsedJson)) { return parsedJson; } throw new Error("Invalid JSON input not an array"); } catch (e) { if (type === "loopJson") { throw e; } } } if (type == "loop" || type == "loopLines") { return stdin.split("\n"); } return [stdin]; }; // src/artifacts/output.json var output_default = { name: "handleOutput", code: "export async function handleOutput(output, value, flags) {\n if (output === 'bool') {\n if (flags.emoji) {\n console.log(value ? '\u2705' : '\u274C');\n }\n else if (flags.int) {\n console.log(value ? 1 : 0);\n }\n else if (value) {\n console.log(value);\n }\n }\n else if (output === 'lines') {\n if (Array.isArray(value)) {\n console.log(value.join('\\n'));\n }\n else {\n console.log(value);\n }\n }\n else if (output === 'log' && value !== undefined) {\n console.log(value);\n }\n else if (output === 'stdout') {\n process.stdout.write(value);\n }\n else if (output === 'json') {\n console.log(JSON.stringify(value, null, 2));\n }\n else if (output === 'bash') {\n const code = [value].flat(Infinity).join('\\n');\n if (flags.print) {\n console.log(code);\n }\n else {\n import('node:child_process').then(({ execSync }) => {\n execSync(code, { stdio: 'inherit' });\n });\n }\n }\n}\n" }; // src/artifacts/importer.json var importer_default = { name: "importer", code: "export async function importer(path) {\n const cmd = await import(path);\n if (typeof cmd.command !== 'undefined' && typeof cmd.command.default !== 'undefined') {\n return cmd.command;\n }\n if (typeof cmd.default !== 'undefined' && typeof cmd.default.default !== 'undefined') {\n return cmd.default;\n }\n if (typeof cmd.default !== 'undefined') {\n return cmd;\n }\n throw new Error('No command found');\n}\n" }; // src/artifacts/user-error.json var user_error_default = { name: "UserError", code: "export class UserError extends Error {\n error: Error;\n constructor(error: Error) {\n super(error.message);\n this.error = error;\n }\n}\n" }; // src/artifacts/run.json var run_default = { name: "run", code: "export async function run({ outputType, handleOutput, UserError, func, args, flags }) {\n let value;\n try {\n value = await func(...args);\n }\n catch (e) {\n throw new UserError(e);\n }\n return await handleOutput(outputType, value, flags);\n}\n" }; // src/evaluate/eval-string.ts var evalString = ({ path: path5, outputType, flags, args }) => { if (!path5) { throw new Error("No path provided for subprocess"); } return [ output_default.code, importer_default.code, user_error_default.code, run_default.code, `importer(${JSON.stringify(path5)}).then(cmd => ${run_default.name}({ outputType: ${JSON.stringify(outputType)}, handleOutput: ${output_default.name}, UserError: ${user_error_default.name}, func: cmd.default, args: ${JSON.stringify(args)}.map(v => v === null ? undefined : v), flags: ${JSON.stringify(flags)} }))` ].join("\n"); }; // src/evaluate/eval.ts var import_node_child_process = require("child_process"); async function spawnJsRuntime(runtime, jsCode) { const clonedRuntime = [...runtime]; const main = clonedRuntime.shift(); if (!main) throw new Error("No runtime provided"); return new Promise((resolve, reject) => { const child = (0, import_node_child_process.spawn)(main, [...clonedRuntime, jsCode], { stdio: "inherit" }); child.on("error", reject); child.on("exit", (code) => { resolve(code); }); }); } // src/evaluate/run.ts async function run({ outputType, handleOutput: handleOutput2, UserError: UserError2, func, args, flags }) { let value; try { value = await func(...args); } catch (e) { throw new UserError2(e); } return await handleOutput2(outputType, value, flags); } // src/evaluate/output.ts async function handleOutput(output, value, flags) { if (output === "bool") { if (flags.emoji) { console.log(value ? "\u2705" : "\u274C"); } else if (flags.int) { console.log(value ? 1 : 0); } else if (value) { console.log(value); } } else if (output === "lines") { if (Array.isArray(value)) { console.log(value.join("\n")); } else { console.log(value); } } else if (output === "log" && value !== void 0) { console.log(value); } else if (output === "stdout") { process.stdout.write(value); } else if (output === "json") { console.log(JSON.stringify(value, null, 2)); } else if (output === "bash") { const code = [value].flat(Infinity).join("\n"); if (flags.print) { console.log(code); } else { import("child_process").then(({ execSync }) => { execSync(code, { stdio: "inherit" }); }); } } } // src/utils/user-error.ts var UserError = class extends Error { error; constructor(error) { super(error.message); this.error = error; } }; // src/utils/debug.ts var import_node_util = __toESM(require("util"), 1); function stringToColorCode(str) { let hash = 0; for (let i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); } const color = Math.abs(hash) % 216 + 16; return `\x1B[38;5;${color}m${str}\x1B[0m`; } function debug(namespace) { return function(message, ...args) { if (process.env.DEBUG && namespace.startsWith(process.env.DEBUG)) { process.stdout.write(`${stringToColorCode(namespace)} ${import_node_util.default.format(message, ...args)} `); } }; } // src/utils/parse-args.ts var import_node_util2 = require("util"); function assemblePositials(tokens) { return tokens.map((v) => { if (v.kind === "positional") return v.value; if (v.kind === "option-terminator") return "--"; return null; }).filter((v) => typeof v === "string"); } function parseArgsBeforePositional(options) { const args = options?.args || []; const { tokens } = (0, import_node_util2.parseArgs)({ ...options, strict: false, tokens: true, allowPositionals: true }); const firstPositionalIndex = tokens?.find((v) => v.kind === "positional")?.index ?? -1; if (firstPositionalIndex === -1) { const result = (0, import_node_util2.parseArgs)({ tokens: true, ...options }); const positionals = assemblePositials(result["tokens"]); return { // doing this because dirty [Object: null prototype] on values values: { ...result.values }, positionals }; } const start = args.slice(0, firstPositionalIndex); const rest = args.slice(firstPositionalIndex + 1); const argv = args[firstPositionalIndex]; const parsedStart = (0, import_node_util2.parseArgs)({ ...options, args: start }); return { // doing this because dirty [Object: null prototype] on values values: { ...parsedStart.values }, positionals: [argv, ...rest] }; } // src/utils/fix-argv.ts function fixArgv(argv) { const fixedArgs = []; let currentArg = ""; let quoteChar = ""; argv.forEach((arg) => { const hasDoubleQuote = arg.includes('"'); const hasSingleQuote = arg.includes("'"); const hasAnyQuote = hasDoubleQuote || hasSingleQuote; if (!quoteChar && hasAnyQuote) { quoteChar = hasDoubleQuote ? '"' : "'"; } if (quoteChar) { currentArg += currentArg ? " " + arg : arg; if (arg.endsWith(quoteChar)) { fixedArgs.push(currentArg); currentArg = ""; quoteChar = ""; } } else { fixedArgs.push(arg); } }); if (quoteChar && currentArg) { fixedArgs.push(currentArg); } return fixedArgs; } // src/utils/fix-flags.ts function fixFlags(flags) { return Object.fromEntries( Object.entries(flags).map(([k, v]) => { if (typeof v === "string" && v.startsWith('"') && v.endsWith('"')) return [k, v.slice(1, -1)]; if (typeof v === "string" && v.startsWith("'") && v.endsWith("'")) return [k, v.slice(1, -1)]; return [k, v]; }) ); } // src/evaluate/index.ts async function evaluate(config, argv) { const logger = debug("knevee:evaluate"); logger("start"); const parsedArgs = (0, import_node_util3.parseArgs)({ tokens: true, args: fixArgv(argv), options: config.flags, strict: config.useStrictFlags, allowPositionals: config.positionals.hasRules }); const positionals = assemblePositials(parsedArgs.tokens); const flags = fixFlags(parsedArgs.values); if (flags.help) { logger("help flag is set, printing help text and exiting"); console.log(config.helpText); process.exit(0); } await depCheck(config.dependencies); const stdin = await stdinLoop(config.stdin, stdinAsync); const loopArgs = stdin.map((stdin2, index) => { const clonedPositionals = [...positionals]; logger("stdin loop %d %s", index, stdin2); if (stdin2 && config.useUnshiftStdin === true) { clonedPositionals.push(stdin2); } const [primary, positionalFlags] = config.positionals.validate(clonedPositionals); const out = [...primary, { ...positionalFlags, ...flags }]; return out; }); const runtime = config.runtime && config.runtime.length ? config.runtime : void 0; const subprocess = async (args) => { const jsCode = evalString({ path: config.path, outputType: config.outputType, flags, args }); return await spawnJsRuntime(runtime, jsCode); }; const mainProcess = async (args) => { return run({ outputType: config.outputType, handleOutput, UserError, func: config.default, args, flags }); }; const method = runtime ? subprocess : mainProcess; if (runtime) logger('runtime detected as "%s"', runtime.join(" ")); let results = []; logger('using loop method "%s"', config.useLoopMethod); if (config.useLoopMethod === "for-await") { for (const args of loopArgs) { results.push(await method(args)); } } else if (config.useLoopMethod === "allSettled") { await Promise.allSettled( loopArgs.map(async (args) => { results.push(await method(args)); }) ); } else if (config.useLoopMethod === "all") { await Promise.all( loopArgs.map(async (args) => { results.push(await method(args)); }) ); } if (runtime) { if (results.every((result) => result === 0)) { logger("all subprocess results are 0, returning 0"); return process.exit(0); } else { logger("some subprocess results are not 0, returning 1"); return process.exit(1); } } logger("end"); return results; } // src/command/path-type.ts var import_promises = __toESM(require("fs/promises"), 1); async function pathType(path5) { try { const stat = await import_promises.default.stat(path5); if (stat.isFile()) return { file: path5 }; if (stat.isDirectory()) return { dir: path5 }; return {}; } catch (e) { return {}; } } // src/command/cmd-name.ts var import_node_path = __toESM(require("path"), 1); function cmdName(opt) { const { dir, file } = opt; const relative = import_node_path.default.relative(dir, file); const basename = import_node_path.default.basename(file, import_node_path.default.extname(file)); const coreKeys = import_node_path.default.dirname(relative).split(import_node_path.default.sep).filter((v) => v !== "."); const safeBasename = basename === "index" ? [] : [basename]; const name = [...coreKeys, ...safeBasename]; return { name, path: file }; } // src/command/dirscan.ts var import_promises2 = __toESM(require("fs/promises"), 1); var import_node_path2 = __toESM(require("path"), 1); async function dirscan(dir, depth = 2, ignoreList = ["node_modules"], allowList = [".js", ".ts", ".mjs", ".cjs", ".sh"], initial = true) { const kneveeFilePath = import_node_path2.default.join(dir, ".knevee"); if (initial) { try { await import_promises2.default.access(kneveeFilePath); } catch { throw new Error(`The root directory does not contain a .knevee file: ${dir}`); } } if (depth < 0) return []; const allEntries = await import_promises2.default.readdir(dir, { withFileTypes: true }); const entries = allEntries.filter((entry) => !entry.name.startsWith(".") && !ignoreList.includes(entry.name)); let results = []; for (const entry of entries) { const pathLocation = import_node_path2.default.join(dir, entry.name); if (entry.isDirectory()) { results = results.concat(await dirscan(pathLocation, depth - 1, ignoreList, allowList, false)); } else { if (allowList.length === 0 || allowList.includes(import_node_path2.default.extname(entry.name))) { results.push(pathLocation); } } } return results; } // src/command/search.ts function search(items, argv, keyExtractor) { const relevantArgv = argv.filter((arg) => items.some((item) => keyExtractor(item).includes(arg))); const match = items.find((item) => { const keys = keyExtractor(item); return keys.length === relevantArgv.length && relevantArgv.every((arg) => keys.includes(arg)); }); if (match) { return { match, results: [] }; } const results = items.filter((item) => { const keys = keyExtractor(item); return relevantArgv.every((arg) => keys.includes(arg)) && keys.length >= argv.length; }); return { match: void 0, results }; } // src/options/index.ts var import_node_path3 = __toESM(require("path"), 1); // src/options/options.ts var Options = class { /** The name of the module. (__Defaults to the name of the file__) */ name = []; /** A description of what the module does. */ description = ""; /** A list of dependencies required by the module. */ dependencies = []; /** Positional arguments that the module accepts. Can be specified as an array or a space-separated string. */ positionals = []; /** A mapping of command line flags to their settings. [parseArgs](https://nodejs.org/api/util.html#utilparseargsconfig) */ flags = {}; /** The function that executes when the command is run. */ default = null; // ----- args ----- /** Specifies if the flags should be strictly validated against the provided flags definitions. (Defaults to `true`) */ useStrictFlags = true; /** Determines if stdin should be unshifted into args. (__Defaults to `true`__) */ useUnshiftStdin = true; /** When iterating stdin loop uses `Promise.allSettled` instead of `Promise.all`. (__Defaults to `false`__) */ useLoopMethod = "for-await"; /** * The type of output that the module should produce. (__Defaults to `log`__) * - `bool` - Outputs the result as a boolean value, adds `--emoji`, `--int` flags to command. * - `json` - Outputs the result as a JSON string, pretty prints the result. * - `lines` - Expects an array, and will output each item on a line. * - `log` - Prints the value. * - `stdout` - Prints the value. * - `bash` - Expects function to return string, and executes, adds `--print` flag to the command, which prints the string. * - `false` - Disables output. */ output = "log"; /** * Describes how positional rules translate to function arguments. (__Defaults to `positionalAsObject`__) * - `positionalNamedObject` - Uses name in positionals as key in args. * - `positionalAsArray` - Uses escalating `_` as the key separating `--` in positionals. */ positionalType = void 0; /** * Determines if the module should read from stdin and how. (__Defaults to `false`__) * - `false` - Disables stdin. * - `true` - Reads from stdin * - `loopJson` - Reads from stdin as a JSON array and loops over each item. * - `loopLines` - Reads from stdin as a string and loops over each line. * - `loop` - Reads stdin and does `loopJson` with backup to `loopLines`. */ stdin = false; /** * Set the javscript runtime to evaluate subprocesses under, must expect appending js string. * `node` * `--experimental-strip-types` * `--experimental-detect-module` * `--disable-warning=MODULE_TYPELESS_PACKAGE_JSON` * `--disable-warning=ExperimentalWarning` * `-e` */ runtime = void 0; runtimeKey = "node"; /** path to dir or file */ path = void 0; /** path to dir or file */ __filename = void 0; importMeta = void 0; /** current working directory */ cwd = void 0; /** command arguments */ argv = void 0; /** runs the command as a subprocess */ subprocess = false; }; // src/utils/std-strings.ts function stdStrings(value = []) { if (Array.isArray(value)) { value = value.map((v) => { if (typeof v !== "string") { throw new Error("All items in the array must be strings"); } return v.trim(); }); } else if (typeof value === "string") { value = value.split(" ").map((v) => v.trim()).filter(Boolean); } else { throw new Error("Unable to normalize array"); } return value; } // src/options/flag-options.ts var helpFlags = { help: { type: "boolean", description: "Prints command help message", short: "h" } }; var boolFlags = { emoji: { type: "boolean", description: "Returns boolean value as emoji \u2705 or \u274C", short: "e", default: false }, int: { type: "boolean", description: "Returns boolean value as 1 or 0", short: "i", default: false } }; var bashFlags = { print: { type: "boolean", description: "Prints the bash command instead of running it", short: "p", default: false } }; // src/positional/split-argv.ts function splitArgv(values, splitCount = 1, match = "--") { const result = []; let remainingValues = values; for (let i = 0; i < splitCount; i++) { const matchIndex = remainingValues.indexOf(match); if (matchIndex === -1) { result.push(remainingValues); return result; } result.push(remainingValues.slice(0, matchIndex)); remainingValues = remainingValues.slice(matchIndex + 1); } result.push(remainingValues); return result; } // src/positional/parse-rule.ts function parseRule(rules) { let hasRest = false; let hasOptional = false; let hasRequired = false; let items = []; for (let i = 0; i < rules.length; i++) { const value = rules[i]; const optional = value.startsWith("[") && value.endsWith("]"); const required = value.startsWith("<") && value.endsWith(">"); const rest = value.endsWith("...]") || value.endsWith("...>"); if (!optional && !required) { throw new Error(`Invalid positional: ${value}`); } if (rest) hasRest = true; if (required) hasRequired = true; if (optional) hasOptional = true; if (required && hasOptional) { throw new Error(`Required positional cannot come after an optional one: ${value}`); } if (rest && i !== rules.length - 1) { throw new Error(`Rest positional must be the last one: ${value}`); } if (rest) { items.push({ value, required, name: value.slice(1, -4), rest: true }); } else { items.push({ value, required, name: value.slice(1, -1) }); } } return { items, hasRest, hasRequired, hasOptional }; } // src/positional/validate.ts function validatePositionals(parsed, argv) { const { items, hasRest } = parsed; const requiredPositionals = items.filter((v) => v.required); const releventPositionals = hasRest ? argv : argv.slice(0, items.length).filter((v) => v !== void 0); if (requiredPositionals.length > releventPositionals.length) { const missingPositionals = requiredPositionals.slice(releventPositionals.length); throw new Error(`Missing required positional arguments: ${missingPositionals.map((v) => v.name).join(", ")}`); } if (!hasRest && items.length < argv.length) { const extraPositionals = argv.slice(items.length); throw new Error(`Extra positional arguments: ${extraPositionals.join(", ")}`); } const fillCount = hasRest ? items.length - 1 : items.length; while (releventPositionals.length < fillCount) { releventPositionals.push(void 0); } return releventPositionals; } // src/positional/object.ts var asObject = (results) => { return Object.fromEntries( results.map((value, index) => { const key = "_".repeat(index + 1); return [key, value]; }) ); }; // src/positional/name-object.ts function asNamedObject({ items }, argv) { return items.reduce((acc, curr, index) => { if (curr.rest) { acc[curr.name] = argv.slice(index); } else { acc[curr.name] = argv[index]; } return acc; }, {}); } // src/positional/index.ts function validateType(type) { const validType = ["positionalAsNamedObject", "positionalAsObject", void 0].includes(type); if (type && !validType) { throw new Error(`Invalid positional type: ${type}`); } } function parsePositionals(ambigousRule, type) { const rule = stdStrings(ambigousRule).map((v) => v.replaceAll("[--]", "--")); const ddCount = rule.filter((v) => v === "--").length; const rules = splitArgv(rule, ddCount); const parsedRules = rules.map((v) => parseRule(v)); const names = parsedRules.flatMap((v) => v.items).map((v) => v.name); const uniqueNames = /* @__PURE__ */ new Set(); const duplicates = /* @__PURE__ */ new Set(); names.forEach((name) => uniqueNames.has(name) ? duplicates.add(name) : uniqueNames.add(name)); if (duplicates.size > 0) { throw new Error(`Duplicate positional argument names: ${Array.from(duplicates).join(", ")}`); } validateType(type); const validate = (argv) => { const argvDdCount = argv.filter((v) => v === "--").length; if (argvDdCount > ddCount) { throw new Error("Invalid number of double dashes"); } const argvInstances = splitArgv(argv, ddCount); const results = argvInstances.map((argv2, i) => validatePositionals(parsedRules[i], argv2)); if (type === "positionalAsNamedObject") { const object2 = Object.assign({}, ...parsedRules.map((v, i) => asNamedObject(v, results[i]))); return [[], object2]; } if (type === "positionalAsObject") { const object2 = asObject(results); return [[], object2]; } const object = asObject(results); const primary = object["_"]; delete object["_"]; return [primary, object]; }; const hasRules = Boolean(names.length); return { validate, hasRules, rules: rule }; } // src/utils/help.ts function help(cmd) { return [ `Usage: ${cmd.name.join(" ")} ${cmd.positionalRules.join(" ")}`, cmd.description, cmd.dependencies?.length ? `Requires \`${cmd.dependencies.join(", ")}\` to be installed` : "", ...cmd.table.split("\n").filter(Boolean).map((line) => line.trim()).map((v) => ` ${v}`) ].map((line) => line).filter(Boolean).join("\n"); } // src/utils/table.ts function table(array, opts = {}) { const columnLengths = array[0].map((_, colIndex) => Math.max(...array.map((row) => row[colIndex].toString().length))); opts = typeof opts === "function" ? opts(columnLengths) : opts; const padCharacter = " "; const gap = Array.isArray(opts.gap) ? opts.gap : Array(array[0].length).fill(opts.gap || 1); const truncate = Array.isArray(opts.truncate) ? opts.truncate : [opts.truncate]; const adjustedColumnLengths = columnLengths.map( (length, colIndex) => Math.min(length, truncate[colIndex] || truncate[0] || Infinity) ); const tableString = array.map( (row) => row.map((item, colIndex) => { const truncatedItem = item.toString().length > adjustedColumnLengths[colIndex] ? item.toString().slice(0, adjustedColumnLengths[colIndex] - 3) + "..." : item.toString(); return truncatedItem.padEnd(adjustedColumnLengths[colIndex] + (gap[colIndex] || 1), padCharacter); }).join("") ).join("\n"); return tableString; } // src/utils/flag-table.ts function flagTable(flags) { return Object.entries(flags).map(([flag, deets]) => { const type = deets.type === "boolean" ? "" : ` <${deets.type}>`; return [`--${flag} ${type}`.trim(), deets.description || ""]; }); } // src/options/runtimes.ts var runtimes_default = { tsx: ["tsx", "-e"], deno: ["deno", "eval"], node: [ "node", "--experimental-strip-types", "--experimental-detect-module", "--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", "--disable-warning=ExperimentalWarning", "-e" ] }; // src/options/index.ts function getName(mod) { if (typeof mod.name === "string") return [mod.name]; let name = mod.name; if (mod.path && !mod.name.length) { name = [import_node_path3.default.basename(mod.path, import_node_path3.default.extname(mod.path))]; } return name; } function parseOptions(options) { const defaultModuleOptions = new Options(); const mod = { ...defaultModuleOptions, ...options }; const description = mod.description; const name = getName(mod); const dependencies = stdStrings(mod.dependencies); const positionals = parsePositionals(mod.positionals, mod.positionalType); const flags = { ...mod.flags, ...mod.output === "bash" ? bashFlags : {}, ...mod.output === "bool" ? boolFlags : {}, ...helpFlags }; const defaultFunc = mod.default; const fullName = name.join(" "); const outputType = mod.output; const runtime = mod.runtime ? stdStrings(mod.runtime) : mod?.runtimeKey && runtimes_default[mod?.runtimeKey] ? runtimes_default[mod.runtimeKey] : void 0; const filename = mod.__filename || mod.importMeta?.filename; const path5 = filename ? filename : mod.path; const helpText = help({ name, description, dependencies, table: table(flagTable(flags)), positionalRules: positionals.rules }); return { ...mod, name, path: path5, dependencies, positionals, flags, default: defaultFunc, fullName, outputType, helpText, runtime, filename }; } // src/utils/importer.ts async function importer(path5) { const cmd = await import(path5); if (typeof cmd.command !== "undefined" && typeof cmd.command.default !== "undefined") { return cmd.command; } if (typeof cmd.default !== "undefined" && typeof cmd.default.default !== "undefined") { return cmd.default; } if (typeof cmd.default !== "undefined") { return cmd; } throw new Error("No command found"); } // src/command/abs-path.ts var import_node_path4 = __toESM(require("path"), 1); var import_node_os = __toESM(require("os"), 1); function absPath(filePath, cwd) { if (!filePath) { throw new Error("A file path must be provided."); } if (filePath.startsWith("~")) { return import_node_path4.default.normalize(import_node_path4.default.join(import_node_os.default.homedir(), filePath.slice(1))); } if (import_node_path4.default.isAbsolute(filePath)) { return import_node_path4.default.normalize(filePath); } if (cwd) { return import_node_path4.default.normalize(import_node_path4.default.resolve(cwd, filePath)); } return import_node_path4.default.normalize(import_node_path4.default.resolve(filePath)); } // package.json var package_default = { name: "knevee", version: "4.4.1", repository: { type: "git", url: "https://github.com/reggi/packages", directory: "workspaces/knevee" }, license: "MIT", author: "reggi (https://reggi.com)", type: "module", exports: { ".": { import: "./dist/index.js", require: "./dist/index.cjs" } }, main: "dist/index.cjs", bin: { knevee: "dist/bin.cjs", dknevee: "bins/dknevee" }, files: [ "dist/", "src/" ], scripts: { build: "src/build/index.ts && npm run build:only --if-present && npm run style:fix && npm run pkg:fix", "build:only": "tsup --clean ./src/*.ts --format esm,cjs --dts", "build:test": "npm run build && npm run test", "build:watch": "npm run build:only -- --watch", depcheck: "depcheck --ignores='@types/node,tsup,sort-package-json'", lint: "eslint .", "lint:fix": "eslint . --fix", pkg: "sort-package-json --check", "pkg:fix": "sort-package-json", report: "open ./coverage/index.html", style: "prettier --check .", "style:fix": "prettier --write .", test: "npm run test:only && npm run style && npm run typecheck && npm run depcheck && npm run pkg && npm run lint", "test:only": "if [ -d ./test ]; then mcr --import tsx tsx --experimental-test-snapshots --test ./test/*.test.ts ./test/**/*.test.ts; fi", "test:snap": "if [ -d ./test ]; then mcr --import tsx tsx --experimental-test-snapshots --test-update-snapshots --test ./test/*.test.ts ./test/**/*.test.ts; fi", typecheck: "tsc" }, prettier: "@github/prettier-config", dependencies: { which: "^5.0.0" }, devDependencies: { "@github/prettier-config": "^0.0.6", "@types/node": "^22.9.0", "@typescript-eslint/parser": "^8.14.0", depcheck: "^1.4.7", eslint: "^9.15.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-node-specifier": "^1.0.3", "eslint-plugin-treekeeper": "^1.1.1", "eslint-plugin-unused-imports": "^4.1.4", "monocart-coverage-reports": "^2.11.2", prettier: "^3.2.5", "sort-package-json": "^2.10.1", tsup: "^8.3.5", tsx: "^4.19.2", typescript: "^5.6.3", "@types/which": "^3.0.4", "mock-fs": "^5.4.1" }, coverage: 100 }; // src/command/knevee-flags.ts var kneveeFlags = { cwd: { description: "The current working directory", type: "string", short: "C" }, runtime: { description: "The runtime to use", type: "string" }, help: { description: "Prints this help", type: "boolean", short: "h" }, version: { description: "Prints the version", type: "boolean", short: "v" } }; // src/command/index.ts async function command(opt) { const logger = debug("knevee:command"); logger("start"); const runtimeKey = process.argv[0].split("/").pop(); const argvOne = fixArgv(opt?.argv || process.argv.slice(2)); let { values: flags, positionals: argv } = parseArgsBeforePositional({ args: argvOne, options: kneveeFlags, strict: true, allowPositionals: true }); flags = fixFlags(flags); if (flags.version) { console.log(package_default.version); return process.exit(0); } if (flags.help) { console.log( help({ name: ["knevee"], description: "A command line tool that runs other command line tools", table: table(flagTable(kneveeFlags)), positionalRules: stdStrings("[runtime] [--] [flags] [subcommands] [command-args...]") }) ); return process.exit(0); } const cwd = absPath(flags?.cwd || opt?.cwd || process.cwd()); const target = argv.shift(); let { file, dir } = target ? await pathType(absPath(target, cwd)) : {}; if (file) { logger("file match"); const command2 = cmdName({ dir: cwd, file }); logger("end"); return { command: command2, argv }; } if (!dir) { logger("subcommand match"); dir = cwd; target && argv.unshift(target); } else { logger("dir match"); } logger("running dirscan"); const files = await dirscan(dir); const commands = files.map((file2) => cmdName({ dir, file: file2 })); const { match, results } = search(commands, argv, (command2) => command2.name); if (!match && !results.length) { throw new Error("No command found"); } if (match) { logger('matched command "%s"', match.name.join(" ")); logger("end"); return { command: match, argv: argv.slice(match.name.length) }; } const hydratedCommands = await Promise.all( results.map(async ({ name, path: path5 }) => { logger("importing %s", path5); return parseOptions({ name, path: path5, ...await importer(path5) }); }) ); const data = hydratedCommands.map((command2) => [command2.fullName, command2.description]); console.log(table(data, { gap: 5 })); logger("end"); return process.exit(0); } // src/index.ts var count = -1; function knevee(opt) { count = count + 1; const logger = debug(`knevee:${count}`); logger("start %d", count); const filename = opt?.__filename || opt?.importMeta?.filename; logger("filename is set to %s", filename); const executable = async ({ nullifyRuntime } = {}) => { const logger2 = debug(`knevee:executable:${count}`); try { logger2("start"); if (filename) { logger2(`filename match`); const options2 = parseOptions(opt); const argv2 = process.argv.slice(2); if (nullifyRuntime) options2.runtime = void 0; const results2 = await evaluate(options2, argv2); logger2("end"); return results2; } const { command: cmd, argv } = await command(opt); logger2("importing the file for metadata"); const mod = await importer(cmd.path); const options = parseOptions({ ...opt, ...cmd, ...mod }); if (nullifyRuntime) options.runtime = void 0; const results = await evaluate(options, argv); logger2("end"); return results; } catch (e) { logger2("caught error"); if (e instanceof UserError) { logger2("throwing as UserError"); throw e.error; } else { logger2("KNEVEE_THROW=%s", process.env.KNEVEE_THROW); if (e instanceof Error) { if (process.env.KNEVEE_THROW === "true") { throw e; } console.error(e.message); } process.exit(1); } } }; if (filename === process.argv[1]) { logger(`filename and process.argv[1] are the same, running executable`); executable({ nullifyRuntime: true }).catch(() => { process.exit(1); }); } logger("end"); return { ...opt, executable }; } // src/bin.ts knevee().executable();