Directory walkers pruned .git/vendor/node_modules but not .worktrees/, so a repo scan descended into nested git worktrees (e.g. an orchestrator worktree under cms/.worktrees/). Their Go/TS files surfaced as false positives in the standalone-plugin import check and noise in the any-usage warnings. Add ".worktrees" to the skip set across the implicated and common walkers: proto RBAC proto-scan, standalone-plugin imports, frontend extras, go-lint, sqlc-uuid, presets.json, and plugin segmentation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
116 lines
2.8 KiB
Go
116 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"git.dev.alexdunmow.com/block/check-safety/internal/theme"
|
|
)
|
|
|
|
type presetViolation struct {
|
|
file string
|
|
message string
|
|
}
|
|
|
|
type presetJSON struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Theme theme.Theme `json:"theme"`
|
|
}
|
|
|
|
func checkPresets(root string) []presetViolation {
|
|
var violations []presetViolation
|
|
|
|
presetsFiles := findPresetsFiles(root)
|
|
for _, path := range presetsFiles {
|
|
relPath, _ := filepath.Rel(root, path)
|
|
if relPath == "" {
|
|
relPath = path
|
|
}
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
violations = append(violations, presetViolation{
|
|
file: relPath,
|
|
message: fmt.Sprintf("cannot read file: %v", err),
|
|
})
|
|
continue
|
|
}
|
|
|
|
// Strict unmarshal: catches type mismatches (e.g., int where string expected)
|
|
var presets []presetJSON
|
|
decoder := json.NewDecoder(bytes.NewReader(data))
|
|
decoder.DisallowUnknownFields()
|
|
if err := decoder.Decode(&presets); err != nil {
|
|
// Distinguish between unknown fields (warning-worthy) and hard parse errors
|
|
if isUnknownFieldError(err) {
|
|
// Re-try without strict mode to get the actual parse result
|
|
var lenient []presetJSON
|
|
if lenientErr := json.Unmarshal(data, &lenient); lenientErr != nil {
|
|
violations = append(violations, presetViolation{
|
|
file: relPath,
|
|
message: fmt.Sprintf("invalid JSON: %v", lenientErr),
|
|
})
|
|
} else {
|
|
violations = append(violations, presetViolation{
|
|
file: relPath,
|
|
message: fmt.Sprintf("unknown fields (stale preset data): %v", err),
|
|
})
|
|
}
|
|
} else {
|
|
violations = append(violations, presetViolation{
|
|
file: relPath,
|
|
message: fmt.Sprintf("invalid JSON: %v", err),
|
|
})
|
|
}
|
|
continue
|
|
}
|
|
|
|
for i, p := range presets {
|
|
if p.ID == "" {
|
|
violations = append(violations, presetViolation{
|
|
file: relPath,
|
|
message: fmt.Sprintf("preset[%d]: missing \"id\" field", i),
|
|
})
|
|
}
|
|
if p.Name == "" {
|
|
violations = append(violations, presetViolation{
|
|
file: relPath,
|
|
message: fmt.Sprintf("preset[%d]: missing \"name\" field", i),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
return violations
|
|
}
|
|
|
|
func findPresetsFiles(root string) []string {
|
|
var files []string
|
|
_ = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil || info.IsDir() {
|
|
if info != nil && info.IsDir() {
|
|
switch info.Name() {
|
|
case ".git", ".worktrees", "vendor", "node_modules", "web", "dist":
|
|
return filepath.SkipDir
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
if info.Name() == "presets.json" {
|
|
files = append(files, path)
|
|
}
|
|
return nil
|
|
})
|
|
return files
|
|
}
|
|
|
|
func isUnknownFieldError(err error) bool {
|
|
return strings.Contains(err.Error(), "unknown field")
|
|
}
|