# 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
