1package server
2
3import (
4 "bytes"
5 "go/parser"
6 "go/token"
7 "path/filepath"
8 "strings"
9)
10
11// IsAutogeneratedPath reports whether a file path suggests it's autogenerated.
12// This checks for common autogenerated file patterns based on path alone.
13func IsAutogeneratedPath(path string) bool {
14 base := filepath.Base(path)
15
16 // Convert path separators to forward slashes for consistent matching
17 normPath := filepath.ToSlash(path)
18
19 // Check directory patterns first
20 // We check if any path component matches the autogenerated directory name
21 for _, d := range autogeneratedDirs {
22 // Match at start of path or after a /
23 if strings.HasPrefix(normPath, d) || strings.Contains(normPath, "/"+d) {
24 return true
25 }
26 }
27
28 // Check file extension patterns
29 for _, ext := range autogeneratedExtensions {
30 if strings.HasSuffix(base, ext) {
31 return true
32 }
33 }
34
35 // Check exact filename matches
36 for _, name := range autogeneratedFilenames {
37 if base == name {
38 return true
39 }
40 }
41
42 return false
43}
44
45// IsAutogeneratedFile reports whether a file is autogenerated based on its path and content.
46// For Go files, it also analyzes the content for autogeneration markers.
47func IsAutogeneratedFile(path string, content []byte) bool {
48 if IsAutogeneratedPath(path) {
49 return true
50 }
51
52 // For Go files, check content for autogeneration markers
53 if strings.HasSuffix(path, ".go") && content != nil {
54 return isAutogeneratedGoContent(content)
55 }
56
57 return false
58}
59
60// isAutogeneratedGoContent reports whether a Go file has markers indicating it was autogenerated.
61func isAutogeneratedGoContent(buf []byte) bool {
62 for _, sig := range autogeneratedSignals {
63 if bytes.Contains(buf, sig) {
64 return true
65 }
66 }
67
68 // https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source
69 // "This line must appear before the first non-comment, non-blank text in the file."
70 // Approximate that by looking for it at the top of the file, before the last of the imports.
71 fset := token.NewFileSet()
72 f, err := parser.ParseFile(fset, "x.go", buf, parser.ImportsOnly|parser.ParseComments)
73 if err == nil {
74 for _, cg := range f.Comments {
75 t := strings.ToLower(cg.Text())
76 for _, sig := range autogeneratedHeaderSignals {
77 if strings.Contains(t, sig) {
78 return true
79 }
80 }
81 }
82 }
83
84 return false
85}
86
87// autogeneratedDirs are directory names that typically contain generated files.
88var autogeneratedDirs = []string{
89 "vendor/",
90 "node_modules/",
91 ".git/",
92 "__pycache__/",
93 ".next/",
94 "dist/",
95 "build/",
96 "generated/",
97 "gen/",
98}
99
100// autogeneratedExtensions are file suffixes that indicate autogenerated files.
101var autogeneratedExtensions = []string{
102 ".pb.go", // Protocol buffers
103 ".pb.gw.go", // gRPC gateway
104 "_string.go", // stringer
105 ".gen.go", // general generated Go
106 ".generated.go", // general generated Go
107 "_generated.go", // general generated Go
108 ".mock.go", // mocks
109 "_mock.go", // mocks
110 ".mocks.go", // mocks
111 "_mocks.go", // mocks
112 ".min.js", // minified JS
113 ".min.css", // minified CSS
114 ".d.ts", // TypeScript declarations
115 ".pb.ts", // Protocol buffers TypeScript
116 ".generated.ts", // general generated TypeScript
117 "_generated.ts", // general generated TypeScript
118 ".sql.go", // sqlc generated
119 ".enumer.go", // enumer generated
120 "_easyjson.go", // easyjson generated
121 ".deepcopy.go", // Kubernetes deepcopy
122}
123
124// autogeneratedFilenames are exact filenames that are typically autogenerated.
125var autogeneratedFilenames = []string{
126 "go.sum",
127 "package-lock.json",
128 "yarn.lock",
129 "pnpm-lock.yaml",
130 "Cargo.lock",
131 "Gemfile.lock",
132 "composer.lock",
133 "poetry.lock",
134 "uv.lock",
135}
136
137// autogeneratedSignals are signals that a Go file is autogenerated, when present anywhere in the file.
138var autogeneratedSignals = [][]byte{
139 []byte("\nfunc bindataRead("), // pre-embed bindata packed file
140}
141
142// autogeneratedHeaderSignals are signals that a file is autogenerated, when present at the top of the file.
143var autogeneratedHeaderSignals = []string{
144 // canonical would be `(?m)^// Code generated .* DO NOT EDIT\.$`
145 // but people screw it up, a lot, so be more lenient
146 strings.ToLower("generate"),
147 strings.ToLower("DO NOT EDIT"),
148 strings.ToLower("export by"),
149}