(filePath, relativePath)
| 671 | function getProjectDeps() { |
| 672 | if (_cachedDeps !== null) return _cachedDeps; |
| 673 | try { |
| 674 | const pkgPath = path.join(PROJECT_ROOT, 'package.json'); |
| 675 | const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); |
| 676 | _cachedDeps = { |
| 677 | ...pkg.dependencies, |
| 678 | ...pkg.devDependencies, |
| 679 | }; |
| 680 | } catch { |
| 681 | _cachedDeps = {}; |
| 682 | } |
| 683 | return _cachedDeps; |
| 684 | } |
| 685 | |
| 686 | function dependencyPatternLint(filePath, relativePath) { |
| 687 | // Only check source files |
| 688 | if (!/\.(ts|tsx|js|jsx)$/.test(filePath)) return; |
| 689 | |
| 690 | const config = health.readConfig(); |
| 691 | const patterns = config.dependencyPatterns; |
| 692 | if (!patterns || !Array.isArray(patterns) || patterns.length === 0) return; |
| 693 | |
| 694 | let content; |
| 695 | try { |
| 696 | content = fs.readFileSync(filePath, 'utf8'); |
| 697 | } catch { |
| 698 | return; |
| 699 | } |
| 700 | |
| 701 | const deps = getProjectDeps(); |
| 702 | const warnings = []; |
| 703 | |
| 704 | for (const entry of patterns) { |
| 705 | if (!entry.dependency || !deps[entry.dependency]) continue; |
| 706 | if (!Array.isArray(entry.banned)) continue; |
| 707 | |
| 708 | for (const banned of entry.banned) { |
| 709 | if (content.includes(banned)) { |
| 710 | const msg = entry.message || 'Use the library instead.'; |
no test coverage detected