Skip to content

Commit 1022e36

Browse files
committed
Fix lint script to respect biome.json excludes
The lint script now properly filters out files excluded in biome.json when linting staged files. This prevents pre-commit hook failures when staging files like CHANGELOG.md or package.json that are excluded from linting. Changes: - Read and parse biome.json to extract exclude patterns - Filter staged files against Biome's exclude patterns - Add pattern matching logic to support glob patterns (**, *, etc.)
1 parent c9d806a commit 1022e36

File tree

1 file changed

+64
-2
lines changed

1 file changed

+64
-2
lines changed

scripts/lint.mjs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Provides smart linting that can target affected files or lint everything.
44
*/
55

6-
import { existsSync } from 'node:fs'
6+
import { existsSync, readFileSync } from 'node:fs'
77
import path from 'node:path'
88

99
import { isQuiet } from './utils/flags.mjs'
@@ -35,6 +35,57 @@ const CONFIG_PATTERNS = [
3535
'eslint.config.*',
3636
]
3737

38+
/**
39+
* Get Biome exclude patterns from biome.json.
40+
*/
41+
function getBiomeExcludePatterns() {
42+
try {
43+
const biomeConfigPath = path.join(process.cwd(), 'biome.json')
44+
if (!existsSync(biomeConfigPath)) {
45+
return []
46+
}
47+
48+
const biomeConfig = JSON.parse(readFileSync(biomeConfigPath, 'utf8'))
49+
const includes = biomeConfig['files']?.['includes'] ?? []
50+
51+
// Extract patterns that start with '!' (exclude patterns)
52+
return (
53+
includes
54+
.filter(
55+
pattern => typeof pattern === 'string' && pattern.startsWith('!'),
56+
)
57+
// Remove the '!' prefix
58+
.map(pattern => pattern.slice(1))
59+
)
60+
} catch {
61+
// If we can't read biome.json, return empty array
62+
return []
63+
}
64+
}
65+
66+
/**
67+
* Check if a file matches any of the exclude patterns.
68+
*/
69+
function isExcludedByBiome(file, excludePatterns) {
70+
for (const pattern of excludePatterns) {
71+
// Convert glob pattern to regex-like matching
72+
// Support **/ for directory wildcards and * for filename wildcards
73+
const regexPattern = pattern
74+
// **/ matches any directory
75+
.replace(/\*\*\//g, '.*')
76+
// * matches any characters except /
77+
.replace(/\*/g, '[^/]*')
78+
// Escape dots
79+
.replace(/\./g, '\\.')
80+
81+
const regex = new RegExp(`^${regexPattern}$`)
82+
if (regex.test(file)) {
83+
return true
84+
}
85+
}
86+
return false
87+
}
88+
3889
/**
3990
* Check if we should run all linters based on changed files.
4091
*/
@@ -74,10 +125,21 @@ function filterLintableFiles(files) {
74125
'.yaml',
75126
])
76127

128+
const biomeExcludePatterns = getBiomeExcludePatterns()
129+
77130
return files.filter(file => {
78131
const ext = path.extname(file)
79132
// Only lint files that have lintable extensions AND still exist.
80-
return lintableExtensions.has(ext) && existsSync(file)
133+
if (!lintableExtensions.has(ext) || !existsSync(file)) {
134+
return false
135+
}
136+
137+
// Filter out files excluded by biome.json
138+
if (isExcludedByBiome(file, biomeExcludePatterns)) {
139+
return false
140+
}
141+
142+
return true
81143
})
82144
}
83145

0 commit comments

Comments
 (0)