pi-lens
Version:
Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo
53 lines (49 loc) • 1.77 kB
YAML
# DISABLED (#206): the `not: inside: try_statement` guard needs relational
# matching the runner's interpreter can't execute; without it every sync fs call
# is flagged even inside a try/catch (noise).
id: unchecked-sync-fs
language: TypeScript
severity: warning
message: "Unchecked sync fs call — throws on missing file or permission error"
note: |
Synchronous filesystem calls throw on OS errors (ENOENT, EACCES, EPERM…).
Without a try/catch the process crashes or the error propagates unchecked.
✅ WRAP IN TRY/CATCH:
try {
const stats = fs.statSync(path);
} catch (err) {
if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
// file doesn't exist — handle gracefully
}
throw err;
}
✅ OR USE ASYNC (preferred for hot paths):
const stats = await fs.promises.stat(path).catch(() => null);
rule:
all:
- any:
- pattern: fs.statSync($$$)
- pattern: fs.lstatSync($$$)
- pattern: fs.readFileSync($$$)
- pattern: fs.readdirSync($$$)
- pattern: fs.writeFileSync($$$)
- pattern: fs.appendFileSync($$$)
- pattern: fs.unlinkSync($$$)
- pattern: fs.rmdirSync($$$)
- pattern: fs.rmSync($$$)
- pattern: fs.renameSync($$$)
- pattern: fs.copyFileSync($$$)
- pattern: fs.accessSync($$$)
- pattern: fs.chmodSync($$$)
- pattern: fs.chownSync($$$)
- pattern: fs.truncateSync($$$)
- pattern: fs.realpathSync($$$)
# mkdirSync without { recursive: true } can throw EEXIST
- all:
- pattern: fs.mkdirSync($PATH)
- not:
pattern: fs.mkdirSync($PATH, $$$)
- not:
inside:
stopBy: end
kind: try_statement