syntaxis/.claude/guidelines/nushell/audit-nu-scripts.nu
Jesús Pérez 9cef9b8d57 refactor: consolidate configuration directories
Merge _configs/ into config/ for single configuration directory.
Update all path references.

Changes:
- Move _configs/* to config/
- Update .gitignore for new patterns
- No code references to _configs/ found

Impact: -1 root directory (layout_conventions.md compliance)
2025-12-26 18:36:23 +00:00

322 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env nu
# audit-nu-scripts.nu - Automated Nushell script auditor for 0.109+ compatibility
# Usage: nu .claude/guidelines/nushell/audit-nu-scripts.nu [--fix] [--verbose]
def main [
--fix # Automatically fix simple issues
--verbose # Show detailed output
--output: string = "" # Output report to file
] {
print_header
# Find all Nushell scripts
let scripts = glob **/*.nu | where {|path| not ($path | str starts-with "target/")}
print $"Found ($scripts | length) Nushell script(s) to audit\n"
mut issues = []
mut summary = {
total_scripts: ($scripts | length)
scripts_with_issues: 0
total_issues: 0
critical: 0
warning: 0
info: 0
}
# Audit each script
for script_path in $scripts {
let script_issues = audit_script $script_path $verbose
if ($script_issues | length) > 0 {
$summary.scripts_with_issues = $summary.scripts_with_issues + 1
$summary.total_issues = $summary.total_issues + ($script_issues | length)
# Count by severity
for issue in $script_issues {
match $issue.severity {
"critical" => { $summary.critical = $summary.critical + 1 }
"warning" => { $summary.warning = $summary.warning + 1 }
"info" => { $summary.info = $summary.info + 1 }
_ => {}
}
}
# Add to issues list
$issues = ($issues | append {
script: $script_path
issues: $script_issues
})
}
}
# Print results
print_divider
print_summary $summary
print_divider
if ($issues | length) > 0 {
print "\n📋 DETAILED FINDINGS:\n"
for script_result in $issues {
print_script_issues $script_result.script $script_result.issues
}
}
# Generate report if requested
if $output != "" {
generate_report $issues $summary $output
print $"\n✓ Report saved to: ($output)"
}
# Exit code based on critical issues
if $summary.critical > 0 {
exit 1
}
}
# Audit a single script
def audit_script [path: string, verbose: bool] -> list {
if $verbose {
print $"Auditing: ($path)"
}
mut issues = []
# Read script content
let content = try {
open --raw $path
} catch {
return [{
line: 0
severity: "critical"
category: "file_access"
message: $"Cannot read file: ($path)"
suggestion: "Check file permissions"
}]
}
let lines = $content | lines
# Check 1: Missing shebang
if (($lines | first) !~ "#!/usr/bin/env nu") {
$issues = ($issues | append {
line: 1
severity: "warning"
category: "shebang"
message: "Missing or incorrect shebang"
suggestion: "Add: #!/usr/bin/env nu"
})
}
# Check 2: Old closure syntax (using $in in where/each)
for (idx, line) in ($lines | enumerate) {
let line_num = $idx + 1
# Check for old-style closures
if ($line =~ '\| where \{ \$in') or ($line =~ '\| each \{ \$in') {
$issues = ($issues | append {
line: $line_num
severity: "warning"
category: "closure_syntax"
message: "Old-style closure using $in"
suggestion: "Use explicit parameter: {|x| $x ...} instead of { $in ... }"
})
}
# Check for missing type annotations on exported functions
if ($line =~ 'export def .+\[') and not ($line =~ ': \w+') {
$issues = ($issues | append {
line: $line_num
severity: "info"
category: "type_annotations"
message: "Function parameters missing type annotations"
suggestion: "Add type annotations: [param: type]"
})
}
# Check for unwrap-like patterns (get without -i)
if ($line =~ '\| get [a-zA-Z_]') and not ($line =~ 'get -i') {
if not ($line =~ '\| get \w+ \|') {
# Potentially unsafe get (not in pipeline continuation)
$issues = ($issues | append {
line: $line_num
severity: "info"
category: "null_safety"
message: "Potentially unsafe 'get' without -i flag"
suggestion: "Use 'get -i' for safe access or add error handling"
})
}
}
# Check for hardcoded paths (common anti-pattern)
if ($line =~ '/Users/[^/]+/') or ($line =~ 'C:\\\\') {
$issues = ($issues | append {
line: $line_num
severity: "warning"
category: "hardcoded_paths"
message: "Hardcoded absolute path detected"
suggestion: "Use $env.HOME or relative paths"
})
}
# Check for missing error handling in external commands
if ($line =~ '\^[a-zA-Z_-]+') and not ($line =~ 'try \{') {
# External command not wrapped in try-catch
# Check if previous or next line has try
let has_try = if $idx > 0 {
($lines | get ($idx - 1) | str contains "try")
} else {
false
}
if not $has_try {
$issues = ($issues | append {
line: $line_num
severity: "info"
category: "error_handling"
message: "External command without error handling"
suggestion: "Wrap in try-catch block"
})
}
}
# Check for deprecated mut syntax
if ($line =~ 'let mut ') {
# This is actually fine in 0.109, just noting it
# $issues = append with info if we want to track mutable usage
}
# Check for missing return type annotations
if ($line =~ 'export def .+\]') and not ($line =~ '-> \w+') and not ($line =~ '\{$') {
$issues = ($issues | append {
line: $line_num
severity: "info"
category: "type_annotations"
message: "Function missing return type annotation"
suggestion: "Add return type: ] -> type {"
})
}
}
# Check 3: No error handling in main functions
let has_try = $content | str contains "try"
let has_catch = $content | str contains "catch"
if not ($has_try and $has_catch) {
$issues = ($issues | append {
line: 0
severity: "info"
category: "error_handling"
message: "Script may lack error handling (no try-catch found)"
suggestion: "Add try-catch blocks for robust error handling"
})
}
$issues
}
# Print header
def print_header [] {
print ""
print "╔════════════════════════════════════════════════════════╗"
print "║ Nushell 0.109+ Compatibility Audit Tool ║"
print "║ syntaxis Project - Script Quality Checker ║"
print "╚════════════════════════════════════════════════════════╝"
print ""
}
# Print divider
def print_divider [] {
print "─────────────────────────────────────────────────────────"
}
# Print summary
def print_summary [summary: record] {
print "\n📊 AUDIT SUMMARY:\n"
print $" Total scripts: ($summary.total_scripts)"
print $" Scripts with issues: ($summary.scripts_with_issues)"
print $" Total issues: ($summary.total_issues)"
print ""
print " By Severity:"
print $" (ansi red)● Critical: ($summary.critical)(ansi reset)"
print $" (ansi yellow)● Warnings: ($summary.warning)(ansi reset)"
print $" (ansi cyan)● Info: ($summary.info)(ansi reset)"
}
# Print issues for a script
def print_script_issues [script: string, issues: list] {
print $"\n(ansi cyan)📄 ($script)(ansi reset)"
for issue in $issues {
let severity_icon = match $issue.severity {
"critical" => $"(ansi red)✗(ansi reset)"
"warning" => $"(ansi yellow)⚠(ansi reset)"
"info" => $"(ansi cyan)(ansi reset)"
_ => "•"
}
let line_info = if $issue.line > 0 {
$" (Line ($issue.line))"
} else {
""
}
print $" ($severity_icon) [($issue.category)]($line_info): ($issue.message)"
print $" → ($issue.suggestion)"
}
}
# Generate markdown report
def generate_report [issues: list, summary: record, output_path: string] {
let timestamp = date now | format date "%Y-%m-%d %H:%M:%S"
mut report = $"# Nushell Script Audit Report
Generated: ($timestamp)
## Summary
- **Total Scripts**: ($summary.total_scripts)
- **Scripts with Issues**: ($summary.scripts_with_issues)
- **Total Issues**: ($summary.total_issues)
- Critical: ($summary.critical)
- Warnings: ($summary.warning)
- Info: ($summary.info)
## Detailed Findings
"
for script_result in $issues {
$report = $report + $"\n### ($script_result.script)\n\n"
for issue in $script_result.issues {
let line_ref = if $issue.line > 0 {
$" (Line ($issue.line))"
} else {
""
}
$report = $report + $"- **[($issue.severity | str upcase)] ($issue.category)**($line_ref)
- Issue: ($issue.message)
- Suggestion: ($issue.suggestion)
"
}
}
$report = $report + $"\n## Recommendations
1. Review all **critical** issues immediately
2. Address **warnings** before next release
3. Consider **info** items for code quality improvements
4. Follow guidelines in `.claude/guidelines/nushell/NUSHELL_0.109_GUIDELINES.md`
---
*Generated by syntaxis Nushell Audit Tool*
"
$report | save --force $output_path
}
# Run main if executed directly
main