Script Basics
🌍 Everything is Global!
Section titled “🌍 Everything is Global!”This is the core concept of Bunmagic: All the utilities documented below are available as global variables in your scripts. You don’t need to import anything - just use them directly!
// No imports needed! Just use the globals:const files = await glob("*.ts")const choice = await select("Pick one:", files)await $`echo "You picked ${choice}"`
Command Arguments
Section titled “Command Arguments”All argument parsing utilities are available as global variables:
Type: string[]
Array containing all non-flag arguments passed to the script.
Examples:
// Running: my-script file1.txt file2.txt --verboseconsole.log(args) // ["file1.txt", "file2.txt"]
// Accessing specific argumentsconst [inputFile, outputFile] = args
Type: Record<string, string | boolean | number>
Object containing all flag arguments passed to the script.
Examples:
// Running: my-script --name=value --verbose -n 5console.log(flags) // { name: "value", verbose: true, n: 5 }
// Conditional logic based on flagsif (flags.verbose) { console.log("Running in verbose mode")}
Type: { _: string[], [key: string]: any }
Combined object containing both arguments and flags in a minimist-like format.
Examples:
// Running: my-script file1.txt file2.txt --verboseconsole.log(argv) // { _: ["file1.txt", "file2.txt"], verbose: true }
notMinimist()
Section titled “notMinimist()”Usage: notMinimist(input: string[]): { flags: Record<string, string | number | boolean | undefined>, args: string[] }
Parses command line arguments into structured format with flags and arguments. Used internally to generate the global args
, flags
, and argv
variables.
Parameters:
input
- Array of command line argument strings
Returns:
- Object with
flags
property containing parsed flags andargs
property containing non-flag arguments
Behavior:
- Supports short flags (
-v
) and long flags (--verbose
) - Handles flag values with equals syntax (
--name=value
) - Handles flag values with space syntax (
--port 3000
) - Automatically type casts values (strings “true”/“false” become booleans, numeric strings become integers)
- Flags without values default to
true
Examples:
// Basic flag parsingconst result = notMinimist(["--verbose", "-n", "5", "file.txt"])console.log(result)// { flags: { verbose: true, n: 5 }, args: ["file.txt"] }
// Equals syntax for valuesconst result = notMinimist(["--name=john", "--debug", "input.txt"])console.log(result)// { flags: { name: "john", debug: true }, args: ["input.txt"] }
// Type castingconst result = notMinimist(["--count=10", "--enabled=true", "--disabled=false"])console.log(result)// { flags: { count: 10, enabled: true, disabled: false }, args: [] }
// Mixed arguments and flagsconst result = notMinimist(["file1.txt", "--output", "result.txt", "file2.txt", "--verbose"])console.log(result)// { flags: { output: "result.txt", verbose: true }, args: ["file1.txt", "file2.txt"] }
Script Documentation & Help
Section titled “Script Documentation & Help”Bunmagic scripts can provide automatic help documentation using JSDoc comments. This makes your scripts self-documenting and provides built-in --help
support.
@autohelp Tag
Section titled “@autohelp Tag”Add @autohelp
to your script’s JSDoc comment to enable automatic --help
handling. When users run your script with the --help
flag, they’ll see formatted documentation instead of the script executing.
Example:
/** * Process and transform data files * @autohelp * @usage my-script <input-file> [output-file] [options] * @flag --format <type> Output format (json, csv, xml) * @flag --verbose Show detailed processing information * @flag --dry-run Preview changes without writing files * @alias transform */export default async function() { // When @autohelp is present, running "my-script --help" // will display the documentation instead of executing this code
const [input, output = "output.json"] = args
if (flags.verbose) { console.log(`Processing ${input}...`) }
// ... rest of script}
Available JSDoc Tags
Section titled “Available JSDoc Tags”@autohelp
- Enable automatic —help handling for the script@usage <example>
- Show usage examples in help output@flag <name> <description>
- Document command-line flags@alias <name>
- Create command aliases (can be used multiple times)
showHelp()
Section titled “showHelp()”Type: Function
Display help information for the current script programmatically. Useful when you want custom help behavior or need to show help in response to specific conditions.
Examples:
/** * Advanced file processor * @usage processor <command> [options] * @flag --config <path> Configuration file path */export default async function() { // Custom help logic if (args.length === 0 || flags.help) { await showHelp() throw new Exit(0) }
// Show help for unknown commands const command = args[0] if (!['process', 'validate', 'convert'].includes(command)) { console.error(`Unknown command: ${command}\n`) await showHelp() throw new Exit(1) }
// ... rest of script}
Help Output Format
Section titled “Help Output Format”When help is displayed (either via @autohelp
or showHelp()
), it shows:
- Script name - The command name in bold
- Description - Main script description from JSDoc
- Usage - Usage examples from
@usage
tags - Flags - All documented flags from
@flag
tags - Aliases - Alternative command names from
@alias
tags
Example output:
my-script Process and transform data files
Usage: my-script <input-file> [output-file] [options]
Flags: --format <type> - Output format (json, csv, xml) --verbose - Show detailed processing information --dry-run - Preview changes without writing files
Aliases: transform
Shell Execution
Section titled “Shell Execution”$ (Shell Commands)
Section titled “$ (Shell Commands)”Type: Function
Bun’s shell API is available globally as $
, allowing you to execute shell commands directly from your scripts.
Returns:
- Promise resolving to the command output
Examples:
// Basic command executionawait $`ls -la`
// Capturing command outputconst gitStatus = await $`git status`.text()console.log(gitStatus)
// Handling command errorstry { await $`command-that-might-fail`} catch (error) { console.error(`Command failed: ${error.message}`)}
// Piping commandsawait $`find . -type f -name "*.ts" | grep -v "node_modules"`
$get()
Section titled “$get()”Usage: $get(...properties: Parameters<typeof $>): Promise<string>
Runs a shell command and returns the result as text, even if the command fails. Unlike the regular $
command which throws on errors, $get
always returns a string containing either stdout or stderr.
Parameters:
...properties
- Same parameters as the$
command (template literal or command string)
Returns:
- Promise resolving to stdout text if command succeeds, or stderr text if command fails
Examples:
// Get command output without error handlingconst gitBranch = await $get`git branch --show-current`console.log(`Current branch: ${gitBranch.trim()}`)
// Handle commands that might failconst result = await $get`ls nonexistent-directory`console.log(result) // Will contain error message instead of throwing
// Compare with regular $ commandtry { await $`command-that-fails` // This throws an error} catch (error) { console.error("Command failed")}
// $get doesn't throw - always returns textconst output = await $get`command-that-fails` // Returns error textconsole.log("Command output:", output)
// Useful for checking command availabilityconst which = await $get`which docker`if (which.includes("not found")) { console.log("Docker is not installed")} else { console.log(`Docker found at: ${which.trim()}`)}
Process Control
Section titled “Process Control”Type: class
Utility for cleanly exiting a script with an optional message.
Examples:
// Exit with a messagethrow new Exit("Operation completed successfully")
// Exit with a status codethrow new Exit("Configuration error", 1)
// Exit when a condition is metif (!await isDirectory(targetDir)) { throw new Exit("Target directory doesn't exist")}
Type: Function
Shorthand utility to exit with an error message.
Examples:
// Simple error exitdie("Fatal error occurred")
// Conditional exitif (!configFile) { die("Missing configuration file")}
// With dynamic messageconst missing = checkMissingDependencies()if (missing.length > 0) { die(`Missing dependencies: ${missing.join(", ")}`)}