#!/usr/bin/env bash set -euo pipefail # Script Name: jj # Description: JSON formatting and querying tool (upgrade from alias) # Usage: jj # Format clipboard JSON # jj '.users[0].name' # jq query on clipboard # jj -v # Validate JSON # jj -f file.json # Format file in place # jj -c # Compact JSON (remove whitespace) # cat file.json | jj # Format from stdin VERSION="1.0.0" show_help() { echo -e "\033[1mjj\033[0m - JSON Formatting & Querying Tool v${VERSION}" echo echo -e "\033[1mUSAGE:\033[0m" echo " jj [OPTIONS] [JQ_QUERY]" echo echo -e "\033[1mOPTIONS:\033[0m" echo -e " \033[0;36m-v, --validate\033[0m Validate JSON only (no output)" echo -e " \033[0;36m-f, --file\033[0m Format file in place" echo -e " \033[0;36m-c, --compact\033[0m Compact JSON (remove whitespace)" echo -e " \033[0;36m-i, --stdin\033[0m Read from stdin instead of clipboard" echo -e " \033[0;36m-o, --output\033[0m Write to clipboard (default: stdout)" echo -e " \033[0;36m-h, --help\033[0m Show this help message" echo echo -e "\033[1mEXAMPLES:\033[0m" echo " jj # Format clipboard JSON" echo " jj '.users[0].name' # Query clipboard with jq" echo " jj -v # Validate clipboard JSON" echo " jj -f data.json # Format file in place" echo " jj -c # Compact clipboard JSON" echo " cat file.json | jj # Format from stdin" echo " curl api.com | jj '.data' # Query API response" echo echo -e "\033[1mNOTE:\033[0m" echo " Requires jq to be installed for querying" } # Clipboard functions clip_get() { if command -v xsel &>/dev/null; then xsel --output --clipboard elif command -v xclip &>/dev/null; then xclip -selection clipboard -o else echo "Error: No clipboard tool found" >&2 return 1 fi } clip_set() { if command -v xsel &>/dev/null; then xsel --input --clipboard elif command -v xclip &>/dev/null; then xclip -selection clipboard else echo "Error: No clipboard tool found" >&2 return 1 fi } # Get input (clipboard or stdin) get_input() { if [[ "${use_stdin}" == "true" ]] || [[ ! -t 0 ]]; then # Use stdin if explicitly requested OR if stdin is not a terminal (piped) cat else clip_get fi } # Validate JSON validate_json() { local input=$1 if echo "$input" | jq empty 2>/dev/null; then echo -e "\033[0;32m✓\033[0m Valid JSON" return 0 else echo -e "\033[0;31m✗\033[0m Invalid JSON:" >&2 echo "$input" | jq empty 2>&1 | sed 's/^/ /' >&2 return 1 fi } # Format JSON (pretty print) format_json() { local input=$1 echo "$input" | jq . } # Compact JSON compact_json() { local input=$1 echo "$input" | jq -c . } # Query JSON with jq query_json() { local input=$1 local query=$2 echo "$input" | jq "$query" } # Parse arguments mode="format" use_stdin=false to_clipboard=false file_path="" jq_query="" while [[ $# -gt 0 ]]; do case $1 in -v|--validate) mode="validate" shift ;; -f|--file) mode="file" file_path="$2" shift 2 ;; -c|--compact) mode="compact" shift ;; -i|--stdin) use_stdin=true shift ;; -o|--output) to_clipboard=true shift ;; -h|--help) show_help exit 0 ;; *) # Assume it's a jq query jq_query="$1" mode="query" shift ;; esac done # Check if jq is installed if ! command -v jq &>/dev/null; then echo -e "\033[0;31mError:\033[0m jq is not installed" >&2 echo "Install it with: sudo apt install jq" >&2 exit 1 fi # Main logic case "$mode" in validate) input=$(get_input) validate_json "$input" ;; file) if [[ ! -f "$file_path" ]]; then echo -e "\033[0;31mError:\033[0m File not found: $file_path" >&2 exit 1 fi # Validate first if ! jq empty "$file_path" 2>/dev/null; then echo -e "\033[0;31mError:\033[0m Invalid JSON in file" >&2 jq empty "$file_path" 2>&1 | sed 's/^/ /' >&2 exit 1 fi # Format in place temp_file=$(mktemp) jq . "$file_path" > "$temp_file" mv "$temp_file" "$file_path" echo -e "\033[0;32m✓\033[0m Formatted: $file_path" ;; compact) input=$(get_input) output=$(compact_json "$input") if [[ "$to_clipboard" == "true" ]]; then echo -n "$output" | clip_set echo -e "\033[0;32m✓\033[0m Copied compacted JSON to clipboard" else echo "$output" fi ;; query) input=$(get_input) output=$(query_json "$input" "$jq_query") if [[ "$to_clipboard" == "true" ]]; then echo -n "$output" | clip_set echo -e "\033[0;32m✓\033[0m Copied query result to clipboard" else echo "$output" fi ;; format) input=$(get_input) output=$(format_json "$input") if [[ "$to_clipboard" == "true" ]]; then echo -n "$output" | clip_set echo -e "\033[0;32m✓\033[0m Copied formatted JSON to clipboard" else echo "$output" fi ;; esac