fix(deps): remove programming-language-detection dependency#695
fix(deps): remove programming-language-detection dependency#695
Conversation
Replace github.com/loft-sh/programming-language-detection with inline implementation. The external package used global mutable state and was not thread-safe. The new implementation uses filepath.WalkDir with simple extension-based detection.
📝 WalkthroughWalkthroughThe pull request removes an external programming language detection dependency and replaces it with an internal heuristic that analyzes file extensions by walking the directory tree and counting occurrences, excluding configured directories. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Extract shouldSkipDir helper to bring complexity from 10 to under the cyclop limit of 8.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
pkg/language/language.go (2)
191-194: Consider logging or propagating WalkDir errors for debuggability.Errors from
filepath.WalkDirand the callback are silently discarded. While this "best effort" approach is acceptable for a heuristic, it could mask permission errors or filesystem issues that would be useful to surface during debugging.💡 Optional: Log errors for debugging
If a logger is available in this context:
- _ = filepath.WalkDir(root, func(_ string, d fs.DirEntry, err error) error { + walkErr := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { if err != nil { + // Log but continue - best effort detection return nil } // ... rest of callback }) + // Optionally log walkErr if non-nil🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/language/language.go` around lines 191 - 194, The WalkDir callback currently swallows filesystem errors (the err parameter) and the outer filepath.WalkDir return value is ignored; change the callback to return the received err instead of nil when err != nil, and capture the error returned by filepath.WalkDir to either propagate it up or log it; if a logger (e.g., a passed-in logger or package logger) is available, log a descriptive message including the error when WalkDir returns an error. Target the anonymous func passed to filepath.WalkDir and the surrounding call site to implement this change.
214-221: Non-deterministic result when multiple languages have equal file counts.Go map iteration order is undefined, so when two languages have the same count, the "winner" is unpredictable across runs. This is acceptable for a heuristic but worth noting.
If deterministic behavior is needed (e.g., for testing), consider adding a tie-breaker such as alphabetical ordering.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/language/language.go` around lines 214 - 221, The current loop over the counts map (variables best, max, counts, lang, count) can yield non-deterministic results when two languages have equal counts; update the tie logic so when count > max OR (count == max AND lang is alphabetically smaller than the current best) you set best = lang and max = count, ensuring deterministic alphabetical tie-breaking (handle the initial best value accordingly).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/language/language.go`:
- Around line 103-116: The extension-to-language lookup currently uses
case-sensitive keys in extensionToLanguage, so detectLanguageByExtension should
normalize the extension to lowercase before lookup; update the
detectLanguageByExtension function to call strings.ToLower on the result of
filepath.Ext (or otherwise lowercase the key) and then use that normalized key
to query extensionToLanguage to ensure .PY, .Js, etc. are matched.
---
Nitpick comments:
In `@pkg/language/language.go`:
- Around line 191-194: The WalkDir callback currently swallows filesystem errors
(the err parameter) and the outer filepath.WalkDir return value is ignored;
change the callback to return the received err instead of nil when err != nil,
and capture the error returned by filepath.WalkDir to either propagate it up or
log it; if a logger (e.g., a passed-in logger or package logger) is available,
log a descriptive message including the error when WalkDir returns an error.
Target the anonymous func passed to filepath.WalkDir and the surrounding call
site to implement this change.
- Around line 214-221: The current loop over the counts map (variables best,
max, counts, lang, count) can yield non-deterministic results when two languages
have equal counts; update the tie logic so when count > max OR (count == max AND
lang is alphabetically smaller than the current best) you set best = lang and
max = count, ensuring deterministic alphabetical tie-breaking (handle the
initial best value accordingly).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: df949891-069a-45d9-9a8d-4119ad7046e9
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (2)
go.modpkg/language/language.go
💤 Files with no reviewable changes (1)
- go.mod
| // extensionToLanguage maps file extensions to programming languages. | ||
| var extensionToLanguage = map[string]ProgrammingLanguage{ | ||
| ".js": JavaScript, | ||
| ".ts": TypeScript, | ||
| ".py": Python, | ||
| ".c": C, | ||
| ".cpp": Cpp, | ||
| ".cs": DotNet, | ||
| ".go": Go, | ||
| ".php": PHP, | ||
| ".java": Java, | ||
| ".rs": Rust, | ||
| ".rb": Ruby, | ||
| } |
There was a problem hiding this comment.
Case-sensitive extension matching may miss files.
filepath.Ext() preserves the original case (e.g., .PY for file.PY), but the map keys are all lowercase. Files with uppercase extensions will not be counted.
Consider normalizing the extension to lowercase before lookup:
🔧 Proposed fix
In detectLanguageByExtension, change line 207:
- if lang, ok := extensionToLanguage[filepath.Ext(d.Name())]; ok {
+ if lang, ok := extensionToLanguage[strings.ToLower(filepath.Ext(d.Name()))]; ok {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/language/language.go` around lines 103 - 116, The extension-to-language
lookup currently uses case-sensitive keys in extensionToLanguage, so
detectLanguageByExtension should normalize the extension to lowercase before
lookup; update the detectLanguageByExtension function to call strings.ToLower on
the result of filepath.Ext (or otherwise lowercase the key) and then use that
normalized key to query extensionToLanguage to ensure .PY, .Js, etc. are
matched.
Summary
github.com/loft-sh/programming-language-detectionexternal dependencyfilepath.WalkDirand simple extension-based detectionSummary by CodeRabbit
Chores
Refactor