# Enhanced validation utilities for provisioning tool export def validate-required [ value: any name: string context?: string ] { if ($value | is-empty) { print $"🛑 Required parameter '($name)' is missing or empty" if ($context | is-not-empty) { print $"Context: ($context)" } print $"💡 Please provide a value for '($name)'" return false } true } export def validate-path [ path: string context?: string --must-exist ] { if ($path | is-empty) { print "🛑 Path parameter is empty" if ($context | is-not-empty) { print $"Context: ($context)" } return false } if $must_exist and not ($path | path exists) { print $"🛑 Path '($path)' does not exist" if ($context | is-not-empty) { print $"Context: ($context)" } print "💡 Check if the path exists and you have proper permissions" return false } true } export def validate-command [ command: string context?: string ] { let cmd_exists = (^bash -c $"type -P ($command)" | complete) if $cmd_exists.exit_code != 0 { print $"🛑 Command '($command)' not found in PATH" if ($context | is-not-empty) { print $"Context: ($context)" } print $"💡 Install '($command)' or add it to your PATH" return false } true } export def safe-execute [ command: closure context: string --fallback: closure ] { let result = (do $command | complete) if $result.exit_code != 0 { print $"⚠️ Warning: Error in ($context): ($result.stderr)" if $fallback != null { print "🔄 Executing fallback..." do $fallback } else { print $"🛑 Execution failed in ($context)" print $"Error: ($result.stderr)" } } else { $result.stdout } } export def validate-settings [ settings: record required_fields: list ] { let missing_fields = ($required_fields | where {|field| ($settings | try { get $field } catch { null } | is-empty) }) if ($missing_fields | length) > 0 { print "🛑 Missing required settings fields:" $missing_fields | each {|field| print $" - ($field)"} return false } true } # ============================================================================ # NICKEL VALIDATION (TYPE-SAFE CONFIGS) # ============================================================================ # Check if Nickel is installed and available export def check-nickel-available [] { let nickel_check = (do { which nickel } | complete) if ($nickel_check.exit_code == 0) { let version_output = (do { nickel --version } | complete).stdout | str trim return { available: true version: $version_output } } { available: false version: null error: "Nickel is not installed or not found in PATH" } } # Validate Nickel configuration using nickel typecheck export def validate-nickel-typecheck [ config_path: path ] { if not ($config_path | path exists) { print-setup-error $"Config file not found: ($config_path)" return false } # Check if nickel command is available let nickel_check = (do { which nickel } | complete) if ($nickel_check.exit_code != 0) { print-setup-warning "Nickel not installed - typecheck validation skipped" return true # Don't block if Nickel not available } # Run nickel typecheck let validation = (do { nickel typecheck $config_path } | complete) if ($validation.exit_code == 0) { return true } else { print-setup-error $"Nickel typecheck failed for ($config_path)" if ($validation.stderr | is-not-empty) { print-setup-error $"Error: ($validation.stderr)" } return false } } # Validate Nickel configuration against schema export def validate-nickel-schema [ config_path: path schema_path: path ] { if not ($config_path | path exists) { print-setup-error $"Config file not found: ($config_path)" return false } if not ($schema_path | path exists) { print-setup-error $"Schema file not found: ($schema_path)" return false } # Check if nickel command is available let nickel_check = (do { which nickel } | complete) if ($nickel_check.exit_code != 0) { print-setup-warning "Nickel not installed - schema validation skipped" return true } # For schema validation, we need to check the import chain # This is a simplified validation that checks typecheck passes let validation = (do { nickel typecheck $config_path } | complete) if ($validation.exit_code == 0) { return true } else { print-setup-error $"Nickel schema validation failed for ($config_path)" if ($validation.stderr | is-not-empty) { print-setup-error $"Error: ($validation.stderr)" } return false } } # Validate Nickel composition (base + overlay) export def validate-nickel-composition [ base_path: path overlay_path: path ] { if not ($base_path | path exists) { print-setup-error $"Base config not found: ($base_path)" return false } if not ($overlay_path | path exists) { print-setup-error $"Overlay config not found: ($overlay_path)" return false } # Check if nickel command is available let nickel_check = (do { which nickel } | complete) if ($nickel_check.exit_code != 0) { print-setup-warning "Nickel not installed - composition validation skipped" return true } # Validate both configs individually first let base_validation = (do { nickel typecheck $base_path } | complete) let overlay_validation = (do { nickel typecheck $overlay_path } | complete) if ($base_validation.exit_code != 0) { print-setup-error $"Base composition validation failed for ($base_path)" return false } if ($overlay_validation.exit_code != 0) { print-setup-error $"Overlay composition validation failed for ($overlay_path)" return false } return true } # Validate all Nickel configs in a directory export def validate-all-nickel-configs [ config_dir: path ] { if not ($config_dir | path exists) { print-setup-error $"Config directory not found: ($config_dir)" return { success: false validated: 0 failed: 0 errors: ["Config directory not found"] } } # Find all .ncl files in config directory let ncl_files = (glob $"($config_dir)/**/*.ncl" | default []) if ($ncl_files | is-empty) { return { success: true validated: 0 failed: 0 errors: [] } } mut validated_count = 0 mut failed_count = 0 mut errors = [] for file in $ncl_files { let validation = (validate-nickel-typecheck $file) if $validation { $validated_count = ($validated_count + 1) } else { $failed_count = ($failed_count + 1) $errors = ($errors | append $file) } } { success: ($failed_count == 0) validated: $validated_count failed: $failed_count errors: $errors } }