From 4775de64eb752b90267114c0c1c95235820521f3 Mon Sep 17 00:00:00 2001 From: "Alex Pooley (@zuedev)" Date: Thu, 5 Feb 2026 16:03:08 +0000 Subject: add CLI validators in Node.js, PowerShell, and Bash Move validate.js to validators/nodejs/ and add equivalent validators for PowerShell and Bash. Each includes a README with usage instructions and requirements. --- validators/bash/validate.sh | 172 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 validators/bash/validate.sh (limited to 'validators/bash/validate.sh') diff --git a/validators/bash/validate.sh b/validators/bash/validate.sh new file mode 100644 index 0000000..55324f1 --- /dev/null +++ b/validators/bash/validate.sh @@ -0,0 +1,172 @@ +#!/usr/bin/env bash + +# CLI validator for .gitinfo files +# Usage: ./validate.sh [file] +# ./validate.sh # validates .gitinfo in current directory +# ./validate.sh path/to/.gitinfo + +set -e + +# Schema path (two levels up from validators/bash/) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCHEMA_PATH="$SCRIPT_DIR/../../gitinfo.schema.json" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color + +# Check for jq +if ! command -v jq &> /dev/null; then + echo -e "${RED}Error: jq is required but not installed.${NC}" >&2 + echo "Install with: apt install jq / brew install jq / choco install jq" >&2 + exit 1 +fi + +# Strip JSONC comments using sed +strip_comments() { + # Remove single-line comments (// ...) and multi-line comments (/* ... */) + # This is a simplified version - doesn't handle comments inside strings perfectly + sed -e 's|//.*$||g' -e ':a;s|/\*.*\*/||g;ta' -e '/\/\*/,/\*\//d' "$1" +} + +# Validate URI format +validate_uri() { + local uri="$1" + if [[ "$uri" =~ ^https?:// ]]; then + return 0 + fi + return 1 +} + +# Validate email format +validate_email() { + local email="$1" + if [[ "$email" =~ ^[^[:space:]@]+@[^[:space:]@]+\.[^[:space:]@]+$ ]]; then + return 0 + fi + return 1 +} + +# Main validation function +validate() { + local file="$1" + local errors=() + + # Parse JSON + local json + if ! json=$(strip_comments "$file" | jq -c . 2>&1); then + echo -e "${RED}Error parsing JSONC: $json${NC}" >&2 + exit 1 + fi + + # Load schema + local schema + if ! schema=$(jq -c . "$SCHEMA_PATH" 2>&1); then + echo -e "${RED}Error parsing schema: $schema${NC}" >&2 + exit 1 + fi + + # Check if root is an object + local type + type=$(echo "$json" | jq -r 'type') + if [[ "$type" != "object" ]]; then + errors+=("root: expected object, got $type") + fi + + # Get allowed properties from schema + local allowed_props + allowed_props=$(echo "$schema" | jq -r '.properties | keys[]') + + # Check for unknown properties + local actual_props + actual_props=$(echo "$json" | jq -r 'keys[]') + for prop in $actual_props; do + if ! echo "$allowed_props" | grep -qx "$prop"; then + errors+=("root: unknown property \"$prop\"") + fi + done + + # Validate each property + local schema_props + schema_props=$(echo "$schema" | jq -r '.properties | to_entries[] | @base64') + + for entry in $schema_props; do + local key format prop_type + key=$(echo "$entry" | base64 -d | jq -r '.key') + format=$(echo "$entry" | base64 -d | jq -r '.value.format // empty') + prop_type=$(echo "$entry" | base64 -d | jq -r '.value.type') + + # Check if property exists + local value + value=$(echo "$json" | jq -r --arg k "$key" '.[$k] // empty') + + if [[ -n "$value" && "$value" != "null" ]]; then + local actual_type + actual_type=$(echo "$json" | jq -r --arg k "$key" '.[$k] | type') + + # Type check + if [[ "$prop_type" == "string" && "$actual_type" != "string" ]]; then + errors+=(".$key: expected string") + elif [[ "$prop_type" == "array" && "$actual_type" != "array" ]]; then + errors+=(".$key: expected array") + fi + + # Format validation for strings + if [[ "$actual_type" == "string" ]]; then + if [[ "$format" == "uri" ]]; then + if ! validate_uri "$value"; then + errors+=(".$key: invalid URI \"$value\"") + fi + elif [[ "$format" == "email" ]]; then + if ! validate_email "$value"; then + errors+=(".$key: invalid email \"$value\"") + fi + fi + fi + + # Validate array items + if [[ "$actual_type" == "array" ]]; then + local item_format + item_format=$(echo "$entry" | base64 -d | jq -r '.value.items.format // empty') + + if [[ "$item_format" == "uri" ]]; then + local i=0 + while IFS= read -r item; do + if ! validate_uri "$item"; then + errors+=(".${key}[$i]: invalid URI \"$item\"") + fi + ((i++)) + done < <(echo "$json" | jq -r --arg k "$key" '.[$k][]?') + fi + fi + fi + done + + # Output results + if [[ ${#errors[@]} -gt 0 ]]; then + echo -e "${RED}Validation failed for $file:${NC}" >&2 + for error in "${errors[@]}"; do + echo -e " - $error" >&2 + done + exit 1 + fi + + echo -e "${GREEN}✓ $file is valid${NC}" + exit 0 +} + +# Main +FILE="${1:-.gitinfo}" + +if [[ ! -f "$FILE" ]]; then + echo -e "${RED}Error: File not found: $FILE${NC}" >&2 + exit 1 +fi + +if [[ ! -f "$SCHEMA_PATH" ]]; then + echo -e "${RED}Error: Schema not found: $SCHEMA_PATH${NC}" >&2 + exit 1 +fi + +validate "$FILE" -- cgit v1.2.3