PureYAML/scripts/check-forbidden-patterns.sh

86 lines
3.1 KiB
Bash

#!/usr/bin/env bash
# Repo contract gate for PureYAML "never" rules.
#
# These checks cover patterns that Swift unit tests cannot see reliably:
# package dependencies, source imports, C/generated parser files, XCTest-style
# tests, platform branches, and singleton/service-locator wiring.
set -u
FAIL=0
fail() {
echo "forbidden-patterns: $1" >&2
FAIL=1
}
report_matches() {
message="$1"
matches="$2"
if [ -n "$matches" ]; then
fail "$message"
printf '%s\n' "$matches" | sed 's/^/ /' >&2
fi
}
if ! grep -qE '^[[:space:]]*dependencies:[[:space:]]*\[[[:space:]]*\],[[:space:]]*$' Package.swift; then
fail "Package.swift must keep dependencies: []"
fi
package_forbidden=$(
grep -nE '\.package[[:space:]]*\(|\.binaryTarget[[:space:]]*\(|\.systemLibrary[[:space:]]*\(' Package.swift 2>/dev/null || true
)
report_matches "Package.swift must not declare external, binary, or system-library targets" "$package_forbidden"
source_imports=$(
grep -RInE '^[[:space:]]*import[[:space:]]+[A-Za-z_][A-Za-z0-9_]*' Sources --include '*.swift' 2>/dev/null || true
)
report_matches "Sources must stay standard-library-only and import no modules" "$source_imports"
source_platform_branches=$(
grep -RInE '^[[:space:]]*#if[[:space:]]+(os|canImport)[[:space:]]*\(' Sources --include '*.swift' 2>/dev/null || true
)
report_matches "Sources must not add platform-specific branches without an explicit rule change" "$source_platform_branches"
source_runtimes=$(
find Sources -type f \( \
-name '*.c' -o \
-name '*.cc' -o \
-name '*.cpp' -o \
-name '*.h' -o \
-name '*.hpp' -o \
-name '*.m' -o \
-name '*.mm' -o \
-name '*.js' -o \
-name '*.ts' -o \
-name '*.wasm' -o \
-name '*.y' -o \
-name '*.l' -o \
-name '*.g4' \
\) -print 2>/dev/null
)
report_matches "Sources must not contain C, JavaScript, WebAssembly blobs, or generated parser runtime files" "$source_runtimes"
source_singletons=$(
grep -RInE 'static[[:space:]]+(let|var)[[:space:]]+shared\b|^[[:space:]]*(public[[:space:]]+)?(final[[:space:]]+)?(class|struct|enum)[[:space:]]+ServiceLocator\b|[A-Za-z0-9_]*(Resolver|Container|Environment)[[:space:]]*\.[[:space:]]*shared\b' Sources --include '*.swift' 2>/dev/null || true
)
report_matches "Sources must not introduce singleton or service-locator access patterns" "$source_singletons"
test_imports=$(
grep -RInE '^[[:space:]]*(@testable[[:space:]]+)?import[[:space:]]+[A-Za-z_][A-Za-z0-9_]*' Tests --include '*.swift' 2>/dev/null \
| grep -vE '^[^:]+:[0-9]+:[[:space:]]*@testable[[:space:]]+import[[:space:]]+PureYAML[[:space:]]*$' \
| grep -vE '^[^:]+:[0-9]+:[[:space:]]*import[[:space:]]+Testing[[:space:]]*$' || true
)
report_matches "Tests may import only Testing and @testable PureYAML" "$test_imports"
test_xctest=$(
grep -RInE '\bXCTest(Case|Expectation)?\b|\bXCTAssert[A-Za-z]*\b|^[[:space:]]*import[[:space:]]+XCTest[[:space:]]*$' Tests --include '*.swift' 2>/dev/null || true
)
report_matches "Tests must stay on Swift Testing and avoid XCTest-style APIs" "$test_xctest"
if [ "$FAIL" -eq 0 ]; then
echo "forbidden-patterns: OK"
fi
exit "$FAIL"