package main import ( "go/parser" "go/token" "os" "path/filepath" "regexp" "strconv" "strings" ) const ( blockCoreImportPrefix = "git.dev.alexdunmow.com/block/core" blockNinjaImportPrefix = "git.dev.alexdunmow.com/block/cms" ) type pluginImportViolation struct { file string line int importPath string } var templImportPattern = regexp.MustCompile(`"([^"]+)"`) func shouldCheckStandalonePluginImports(root string) bool { return isPluginModuleRoot(root) && !isBundledPluginRoot(root) } func isBundledPluginRoot(root string) bool { bundledPluginsDir := filepath.Join(blockNinjaRepoRoot(), "backend", "internal", "plugins") absRoot, err := filepath.Abs(root) if err != nil { return false } absBundledPluginsDir, err := filepath.Abs(bundledPluginsDir) if err != nil { return false } rel, err := filepath.Rel(absBundledPluginsDir, absRoot) if err != nil { return false } if rel == "." { return false } return !strings.HasPrefix(rel, ".."+string(filepath.Separator)) && rel != ".." } func checkStandalonePluginImports(root string) []pluginImportViolation { var violations []pluginImportViolation _ = filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return nil } if info.IsDir() { switch info.Name() { case ".git", ".worktrees", "vendor", "node_modules": return filepath.SkipDir } return nil } relPath, _ := filepath.Rel(root, path) if strings.HasSuffix(path, ".templ") { data, readErr := os.ReadFile(path) if readErr != nil { return nil } lines := strings.Split(string(data), "\n") for i, line := range lines { if !strings.Contains(line, blockNinjaImportPrefix) { continue } matches := templImportPattern.FindAllStringSubmatch(line, -1) for _, match := range matches { importPath := match[1] if !strings.HasPrefix(importPath, blockNinjaImportPrefix) { continue } violations = append(violations, pluginImportViolation{ file: relPath, line: i + 1, importPath: importPath, }) } } return nil } if !strings.HasSuffix(path, ".go") { return nil } fset := token.NewFileSet() file, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly) if err != nil { return nil } for _, spec := range file.Imports { importPath, err := strconv.Unquote(spec.Path.Value) if err != nil { continue } if !strings.HasPrefix(importPath, blockNinjaImportPrefix) { continue } pos := fset.Position(spec.Pos()) violations = append(violations, pluginImportViolation{ file: relPath, line: pos.Line, importPath: importPath, }) } return nil }) return violations }