Add composable multi-language linting and formatting system
PostToolUse hook auto-formats files after Edit/Write/MultiEdit with git-blob checkpoints for safe revert. Pre-commit hook for staged files. Canonical formatter scripts for py, sh, ts, sql, json (+ symlinks for js, yaml, md). Install and setup scripts for project opt-in. Includes best-practices/linting.md, HOOKS.md docs, README.md, and session log. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1
formatters/js
Symbolic link
1
formatters/js
Symbolic link
@@ -0,0 +1 @@
|
||||
ts
|
||||
19
formatters/json
Executable file
19
formatters/json
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Formatter: JSON/YAML/Markdown — prettier
|
||||
# Contract: $1 = absolute file path, format in place, lint, exit 0 if clean / 1 if errors
|
||||
# Missing tools: exit 0 silently
|
||||
|
||||
FILE="$1"
|
||||
[ -z "$FILE" ] && exit 0
|
||||
[ -f "$FILE" ] || exit 0
|
||||
|
||||
command -v prettier >/dev/null 2>&1 || exit 0
|
||||
|
||||
# Format in place (prettier auto-detects parser from extension)
|
||||
ERRORS=$(prettier --write "$FILE" 2>&1)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$ERRORS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
1
formatters/md
Symbolic link
1
formatters/md
Symbolic link
@@ -0,0 +1 @@
|
||||
json
|
||||
25
formatters/py
Executable file
25
formatters/py
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
# Formatter: Python — ruff format + ruff check
|
||||
# Contract: $1 = absolute file path, format in place, lint, exit 0 if clean / 1 if errors
|
||||
# Missing tools: exit 0 silently
|
||||
|
||||
FILE="$1"
|
||||
[ -z "$FILE" ] && exit 0
|
||||
[ -f "$FILE" ] || exit 0
|
||||
|
||||
command -v ruff >/dev/null 2>&1 || exit 0
|
||||
|
||||
# Format in place
|
||||
ruff format --quiet "$FILE" 2>/dev/null
|
||||
|
||||
# Auto-fix what we can
|
||||
ruff check --fix --quiet "$FILE" 2>/dev/null
|
||||
|
||||
# Final lint pass — remaining errors go to stderr
|
||||
ERRORS=$(ruff check "$FILE" 2>&1)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$ERRORS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
31
formatters/sh
Executable file
31
formatters/sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Formatter: Shell — shfmt + shellcheck
|
||||
# Contract: $1 = absolute file path, format in place, lint, exit 0 if clean / 1 if errors
|
||||
# Missing tools: exit 0 silently
|
||||
|
||||
FILE="$1"
|
||||
[ -z "$FILE" ] && exit 0
|
||||
[ -f "$FILE" ] || exit 0
|
||||
|
||||
HAD_ERRORS=0
|
||||
|
||||
# Format with shfmt if available
|
||||
if command -v shfmt >/dev/null 2>&1; then
|
||||
shfmt -w "$FILE" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Lint with shellcheck if available
|
||||
if command -v shellcheck >/dev/null 2>&1; then
|
||||
ERRORS=$(shellcheck -f gcc "$FILE" 2>&1)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$ERRORS" >&2
|
||||
HAD_ERRORS=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# If neither tool is installed, silently pass
|
||||
if ! command -v shfmt >/dev/null 2>&1 && ! command -v shellcheck >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit $HAD_ERRORS
|
||||
22
formatters/sql
Executable file
22
formatters/sql
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# Formatter: SQL — sqlfluff fix + sqlfluff lint
|
||||
# Contract: $1 = absolute file path, format in place, lint, exit 0 if clean / 1 if errors
|
||||
# Missing tools: exit 0 silently
|
||||
|
||||
FILE="$1"
|
||||
[ -z "$FILE" ] && exit 0
|
||||
[ -f "$FILE" ] || exit 0
|
||||
|
||||
command -v sqlfluff >/dev/null 2>&1 || exit 0
|
||||
|
||||
# Auto-fix in place
|
||||
sqlfluff fix --force --quiet "$FILE" 2>/dev/null
|
||||
|
||||
# Final lint pass — remaining errors go to stderr
|
||||
ERRORS=$(sqlfluff lint "$FILE" 2>&1)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$ERRORS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
25
formatters/ts
Executable file
25
formatters/ts
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
# Formatter: TypeScript/JavaScript — biome format + biome check
|
||||
# Contract: $1 = absolute file path, format in place, lint, exit 0 if clean / 1 if errors
|
||||
# Missing tools: exit 0 silently
|
||||
|
||||
FILE="$1"
|
||||
[ -z "$FILE" ] && exit 0
|
||||
[ -f "$FILE" ] || exit 0
|
||||
|
||||
command -v biome >/dev/null 2>&1 || exit 0
|
||||
|
||||
# Format in place
|
||||
biome format --write "$FILE" 2>/dev/null
|
||||
|
||||
# Auto-fix what we can
|
||||
biome check --fix "$FILE" 2>/dev/null
|
||||
|
||||
# Final lint pass — remaining errors go to stderr
|
||||
ERRORS=$(biome check "$FILE" 2>&1)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$ERRORS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
1
formatters/yaml
Symbolic link
1
formatters/yaml
Symbolic link
@@ -0,0 +1 @@
|
||||
json
|
||||
Reference in New Issue
Block a user