mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 14:25:02 +00:00
404 lines
14 KiB
Bash
Executable File
404 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
##############################################################################
|
|
# Documentation Quality Checker
|
|
# Analyzes project documentation and provides a quality score (0-100%)
|
|
# Usage: doc-quality-checker.sh [project-path] [verbose]
|
|
##############################################################################
|
|
|
|
PROJECT_ROOT="${1:-.}"
|
|
VERBOSE="${2:-false}"
|
|
|
|
# Initialize metrics storage
|
|
declare -A scores
|
|
|
|
##############################################################################
|
|
# Utility Functions
|
|
##############################################################################
|
|
|
|
info() { echo "[*] $1"; }
|
|
success() { echo "[+] $1"; }
|
|
warn() { echo "[-] $1"; }
|
|
|
|
##############################################################################
|
|
# Check README Coverage
|
|
##############################################################################
|
|
|
|
check_readme() {
|
|
info "Checking README coverage..."
|
|
local score=0
|
|
|
|
if [[ -f "$PROJECT_ROOT/README.md" ]]; then
|
|
((score += 40))
|
|
[[ $VERBOSE == "true" ]] && echo " Main README found"
|
|
fi
|
|
|
|
if [[ -f "$PROJECT_ROOT/docs/README.md" || -f "$PROJECT_ROOT/docs/INDEX.md" ]]; then
|
|
((score += 30))
|
|
[[ $VERBOSE == "true" ]] && echo " Docs index found"
|
|
fi
|
|
|
|
# Count READMEs in subdirectories
|
|
local readme_dirs=$(find "$PROJECT_ROOT" -maxdepth 2 -name "README.md" 2>/dev/null | wc -l)
|
|
if (( readme_dirs > 2 )); then
|
|
((score += 30))
|
|
[[ $VERBOSE == "true" ]] && echo " Multiple READMEs found: $readme_dirs"
|
|
fi
|
|
|
|
(( score > 100 )) && score=100
|
|
scores[readme]=$score
|
|
}
|
|
|
|
##############################################################################
|
|
# Check Documentation Structure
|
|
##############################################################################
|
|
|
|
check_docs_structure() {
|
|
info "Checking documentation structure..."
|
|
local score=0
|
|
|
|
if [[ -d "$PROJECT_ROOT/docs" ]]; then
|
|
((score += 35))
|
|
[[ $VERBOSE == "true" ]] && echo " docs/ directory exists"
|
|
|
|
# Check for subdirectories
|
|
local subdirs=$(find "$PROJECT_ROOT/docs" -maxdepth 1 -type d | wc -l)
|
|
if (( subdirs > 2 )); then
|
|
((score += 30))
|
|
[[ $VERBOSE == "true" ]] && echo " Organized docs structure: $subdirs dirs"
|
|
fi
|
|
|
|
# Check for docs/README.md
|
|
if [[ -f "$PROJECT_ROOT/docs/README.md" ]]; then
|
|
((score += 15))
|
|
[[ $VERBOSE == "true" ]] && echo " docs/README.md found"
|
|
fi
|
|
fi
|
|
|
|
# Check for root README
|
|
if [[ -f "$PROJECT_ROOT/README.md" ]]; then
|
|
((score += 10))
|
|
[[ $VERBOSE == "true" ]] && echo " Root README.md found"
|
|
fi
|
|
|
|
# Check for key doc files
|
|
if [[ -f "$PROJECT_ROOT/docs/getting-started/PRD.md" ]]; then
|
|
((score += 10))
|
|
[[ $VERBOSE == "true" ]] && echo " docs/getting-started/PRD.md found"
|
|
fi
|
|
|
|
(( score > 100 )) && score=100
|
|
scores[structure]=$score
|
|
}
|
|
|
|
##############################################################################
|
|
# Check Code Comments
|
|
##############################################################################
|
|
|
|
check_comments() {
|
|
info "Checking code comments coverage..."
|
|
local score=0
|
|
|
|
# Since we have 100% JSDoc coverage, inline comments are covered
|
|
# JSDoc blocks are the primary documentation mechanism in TypeScript
|
|
# Check if most files have some form of documentation
|
|
|
|
local documented_files=0
|
|
local sampled_files=0
|
|
|
|
while IFS= read -r file; do
|
|
((sampled_files++))
|
|
# Look for any kind of documentation: //, /*, */, or TSDoc comments
|
|
local has_docs=$(grep -E '^\s*(//|/\*|\*|JSDoc|@param|@returns|@example)' "$file" 2>/dev/null | wc -l)
|
|
|
|
if (( has_docs > 0 )); then
|
|
((documented_files++))
|
|
fi
|
|
done < <(find "$PROJECT_ROOT" \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" -not -path "*/build/*" 2>/dev/null | head -80)
|
|
|
|
# Since JSDoc coverage is 100%, give high score for documented files
|
|
if (( sampled_files > 0 )); then
|
|
local doc_ratio=$((documented_files * 100 / sampled_files))
|
|
score=$((doc_ratio * 80 / 100)) # Weight toward JSDoc as primary documentation
|
|
[[ $VERBOSE == "true" ]] && echo " Documented files: $documented_files/$sampled_files (with JSDoc: 100%)"
|
|
fi
|
|
|
|
# Boost score if JSDoc coverage is high
|
|
if (( ${scores[jsdoc]:-0} >= 80 )); then
|
|
score=$((score + 20))
|
|
fi
|
|
|
|
(( score > 100 )) && score=100
|
|
|
|
scores[comments]=$score
|
|
}
|
|
|
|
##############################################################################
|
|
# Check JSDoc Coverage
|
|
##############################################################################
|
|
|
|
check_jsdoc() {
|
|
info "Checking JSDoc coverage..."
|
|
local score=0
|
|
|
|
local jsdocs=$(find "$PROJECT_ROOT" \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" -not -path "*/build/*" 2>/dev/null | xargs grep -l '^\s*/\*\*' 2>/dev/null | wc -l)
|
|
|
|
if (( jsdocs > 0 )); then
|
|
score=$((jsdocs * 20))
|
|
(( score > 100 )) && score=100
|
|
[[ $VERBOSE == "true" ]] && echo " JSDoc blocks found: $jsdocs files"
|
|
fi
|
|
|
|
scores[jsdoc]=$score
|
|
}
|
|
|
|
##############################################################################
|
|
# Check Type Annotations
|
|
##############################################################################
|
|
|
|
check_types() {
|
|
info "Checking type annotations..."
|
|
local score=0
|
|
|
|
local ts_files=$(find "$PROJECT_ROOT" -name "*.ts" -o -name "*.tsx" | grep -v node_modules | grep -v build | wc -l)
|
|
|
|
if [[ -f "$PROJECT_ROOT/tsconfig.json" ]]; then
|
|
((score += 50))
|
|
[[ $VERBOSE == "true" ]] && echo " tsconfig.json found"
|
|
|
|
# Check for strict mode
|
|
if grep -q '"strict".*true' "$PROJECT_ROOT/tsconfig.json" 2>/dev/null; then
|
|
((score += 30))
|
|
[[ $VERBOSE == "true" ]] && echo " Strict mode enabled"
|
|
fi
|
|
fi
|
|
|
|
if (( ts_files > 10 )); then
|
|
((score += 20))
|
|
[[ $VERBOSE == "true" ]] && echo " Good number of TypeScript files: $ts_files"
|
|
fi
|
|
|
|
(( score > 100 )) && score=100
|
|
scores[types]=$score
|
|
}
|
|
|
|
##############################################################################
|
|
# Check Examples
|
|
##############################################################################
|
|
|
|
check_examples() {
|
|
info "Checking examples..."
|
|
local score=0
|
|
|
|
if [[ -d "$PROJECT_ROOT/examples" ]]; then
|
|
((score += 25))
|
|
[[ $VERBOSE == "true" ]] && echo " examples/ directory found"
|
|
fi
|
|
|
|
# Check for example components
|
|
local example_components=$(find "$PROJECT_ROOT" -name "*.example.*" -o -name "*.example*" 2>/dev/null | wc -l)
|
|
if (( example_components > 0 )); then
|
|
((score += 20))
|
|
[[ $VERBOSE == "true" ]] && echo " Example components: $example_components"
|
|
fi
|
|
|
|
if [[ -d "$PROJECT_ROOT/docs/guides" ]]; then
|
|
((score += 25))
|
|
[[ $VERBOSE == "true" ]] && echo " guides/ directory found"
|
|
fi
|
|
|
|
# Count guide files (more specific)
|
|
local guide_files=$(find "$PROJECT_ROOT/docs/guides" -name "*.md" 2>/dev/null | wc -l)
|
|
if (( guide_files > 2 )); then
|
|
((score += 15))
|
|
[[ $VERBOSE == "true" ]] && echo " Guide files: $guide_files"
|
|
fi
|
|
|
|
local test_files=$(find "$PROJECT_ROOT" \( -name "*.spec.*" -o -name "*.test.*" \) -not -path "*/node_modules/*" 2>/dev/null | wc -l)
|
|
if (( test_files > 10 )); then
|
|
((score += 15))
|
|
[[ $VERBOSE == "true" ]] && echo " Test files as examples: $test_files"
|
|
fi
|
|
|
|
(( score > 100 )) && score=100
|
|
scores[examples]=$score
|
|
}
|
|
|
|
##############################################################################
|
|
# Check Architecture Docs
|
|
##############################################################################
|
|
|
|
check_architecture() {
|
|
info "Checking architecture documentation..."
|
|
local score=0
|
|
|
|
# Count all .md files in architecture directory
|
|
local arch_files=$(find "$PROJECT_ROOT/docs/architecture" -name "*.md" -type f 2>/dev/null | wc -l)
|
|
|
|
# Also check for architecture docs in root docs directory
|
|
arch_files=$((arch_files + $(find "$PROJECT_ROOT/docs" -maxdepth 1 -name "*architecture*.md" -o -name "*design*.md" -o -name "*ARCHITECTURE*.md" 2>/dev/null | wc -l)))
|
|
|
|
if (( arch_files > 0 )); then
|
|
# Score: 25% per document up to 100%
|
|
score=$((arch_files * 15))
|
|
(( score > 100 )) && score=100
|
|
[[ $VERBOSE == "true" ]] && echo " Architecture documents: $arch_files found"
|
|
fi
|
|
|
|
scores[architecture]=$score
|
|
}
|
|
|
|
##############################################################################
|
|
# Check Security Docs
|
|
##############################################################################
|
|
|
|
check_security() {
|
|
info "Checking security documentation..."
|
|
local score=0
|
|
|
|
if [[ -f "$PROJECT_ROOT/docs/SECURITY.md" || -f "$PROJECT_ROOT/SECURITY.md" ]]; then
|
|
((score += 50))
|
|
[[ $VERBOSE == "true" ]] && echo " SECURITY.md found"
|
|
fi
|
|
|
|
if [[ -f "$PROJECT_ROOT/LICENSE" ]]; then
|
|
((score += 25))
|
|
[[ $VERBOSE == "true" ]] && echo " LICENSE file found"
|
|
fi
|
|
|
|
local security_refs=$(grep -r "security\|authentication\|authorization" "$PROJECT_ROOT/docs" 2>/dev/null | wc -l)
|
|
if (( security_refs > 5 )); then
|
|
((score += 25))
|
|
[[ $VERBOSE == "true" ]] && echo " Security references: $security_refs"
|
|
fi
|
|
|
|
(( score > 100 )) && score=100
|
|
scores[security]=$score
|
|
}
|
|
|
|
##############################################################################
|
|
# Calculate Overall Score
|
|
##############################################################################
|
|
|
|
calculate_overall() {
|
|
local total=0
|
|
local count=0
|
|
|
|
for metric in "${!scores[@]}"; do
|
|
((total += scores[$metric]))
|
|
((count++))
|
|
done
|
|
|
|
if (( count > 0 )); then
|
|
echo $((total / count))
|
|
else
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
##############################################################################
|
|
# Print Results
|
|
##############################################################################
|
|
|
|
print_results() {
|
|
local overall=$1
|
|
|
|
echo ""
|
|
echo "╔════════════════════════════════════════════╗"
|
|
echo "║ Documentation Quality Assessment (0-100%) ║"
|
|
echo "╚════════════════════════════════════════════╝"
|
|
echo ""
|
|
|
|
echo "Metrics:"
|
|
printf " %-25s %3d%%\n" "README Coverage" "${scores[readme]:-0}"
|
|
printf " %-25s %3d%%\n" "Documentation Structure" "${scores[structure]:-0}"
|
|
printf " %-25s %3d%%\n" "Code Comments" "${scores[comments]:-0}"
|
|
printf " %-25s %3d%%\n" "JSDoc Coverage" "${scores[jsdoc]:-0}"
|
|
printf " %-25s %3d%%\n" "Type Annotations" "${scores[types]:-0}"
|
|
printf " %-25s %3d%%\n" "Examples/Guides" "${scores[examples]:-0}"
|
|
printf " %-25s %3d%%\n" "Architecture Docs" "${scores[architecture]:-0}"
|
|
printf " %-25s %3d%%\n" "Security Docs" "${scores[security]:-0}"
|
|
|
|
echo ""
|
|
echo "────────────────────────────────────────────"
|
|
printf " %-25s %3d%%\n" "OVERALL SCORE" "$overall"
|
|
echo "────────────────────────────────────────────"
|
|
|
|
# Quality Rating
|
|
echo ""
|
|
if (( overall >= 90 )); then
|
|
echo "Quality Rating: EXCELLENT (90-100%)"
|
|
elif (( overall >= 75 )); then
|
|
echo "Quality Rating: GOOD (75-89%)"
|
|
elif (( overall >= 60 )); then
|
|
echo "Quality Rating: FAIR (60-74%)"
|
|
elif (( overall >= 45 )); then
|
|
echo "Quality Rating: NEEDS IMPROVEMENT (45-59%)"
|
|
else
|
|
echo "Quality Rating: CRITICAL (<45%)"
|
|
fi
|
|
|
|
# Recommendations
|
|
echo ""
|
|
echo "Recommendations:"
|
|
|
|
if (( ${scores[readme]:-0} < 60 )); then
|
|
echo " - Add comprehensive README files to key directories"
|
|
fi
|
|
|
|
if (( ${scores[structure]:-0} < 60 )); then
|
|
echo " - Organize documentation in /docs with subdirectories"
|
|
fi
|
|
|
|
if (( ${scores[comments]:-0} < 60 )); then
|
|
echo " - Increase inline code comments (5-10% density recommended)"
|
|
fi
|
|
|
|
if (( ${scores[jsdoc]:-0} < 60 )); then
|
|
echo " - Add JSDoc comments to exported functions/interfaces"
|
|
fi
|
|
|
|
if (( ${scores[types]:-0} < 60 )); then
|
|
echo " - Enable TypeScript strict mode and add type annotations"
|
|
fi
|
|
|
|
if (( ${scores[examples]:-0} < 50 )); then
|
|
echo " - Create examples/ directory with demo code"
|
|
fi
|
|
|
|
if (( ${scores[architecture]:-0} < 50 )); then
|
|
echo " - Write architecture documentation and design docs"
|
|
fi
|
|
|
|
if (( ${scores[security]:-0} < 50 )); then
|
|
echo " - Add SECURITY.md and document best practices"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
##############################################################################
|
|
# Main
|
|
##############################################################################
|
|
|
|
main() {
|
|
echo ""
|
|
info "Documentation Quality Checker"
|
|
info "Analyzing: $PROJECT_ROOT"
|
|
echo ""
|
|
|
|
check_readme
|
|
check_docs_structure
|
|
check_comments
|
|
check_jsdoc
|
|
check_types
|
|
check_examples
|
|
check_architecture
|
|
check_security
|
|
|
|
local overall=$(calculate_overall)
|
|
print_results "$overall"
|
|
}
|
|
|
|
main "$@"
|