Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

fs.globSync() uses process.cwd() when building the root exclude Dirent with withFileTypes

Chiusa
#63,535 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
76/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
javascript

Direzione di ricerca

Inizia in lib/internal/fs/glob.js, in #addSubpattern(), confrontando il ramo sincrono di withFileTypes ed exclude con il percorso asincrono. Riproduci il problema con lo script fornito, quindi verifica che il callback di exclude riceva un Dirent per il glob cwd anziché per process.cwd() e che la directory venga esclusa.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

stale
Version

v25.8.2

Platform
Darwin arm64
Subsystem

fs

What steps will reproduce the bug?
const { mkdtempSync, mkdirSync, writeFileSync, globSync } = require('node:fs');
const { tmpdir } = require('node:os');
const { join } = require('node:path');
const { chdir, cwd } = require('node:process');

const base = mkdtempSync(join(tmpdir(), 'glob-root-'));
const ambient = join(base, 'ambient');
const root = join(base, 'root');

mkdirSync(ambient, { recursive: true });
mkdirSync(join(root, 'a'), { recursive: true });
writeFileSync(join(ambient, 'a'), 'shadow-file');
writeFileSync(join(root, 'a', 'real.txt'), 'real');

chdir(ambient);

const seen = [];
const result = globSync('a/**', {
  cwd: root,
  withFileTypes: true,
  exclude: (dirent) => {
    seen.push({
      name: dirent.name,
      parentPath: dirent.parentPath,
      isDirectory: dirent.isDirectory(),
      isFile: dirent.isFile(),
    });
    return dirent.isDirectory();
  },
});

console.log(JSON.stringify({
  processCwd: cwd(),
  globCwd: root,
  seen,
  result: result.map((dirent) => ({
    name: dirent.name,
    parentPath: dirent.parentPath,
    isDirectory: dirent.isDirectory(),
    isFile: dirent.isFile(),
  })),
}, null, 2));
How often does it reproduce? Is there a required condition?

It reproduces consistently in globSync() when all of the following are true:

  • withFileTypes: true
  • cwd !== process.cwd()
  • the pattern goes through the root-entry #addSubpattern() path (for example a/**)

If the ambient process.cwd() also contains the same relative path, the callback receives a Dirent for the ambient path instead of the glob cwd path. If the ambient cwd does not contain that path, the root entry can skip the callback entirely because statSync(path) returns null.

The async glob path does not seem affected.

What is the expected behavior? Why is that the expected behavior?

The exclude callback should receive a Dirent describing the candidate entry under options.cwd.

For the repro above, the callback should receive a directory dirent for <globCwd>/a, so dirent.isDirectory() should be true and the result should be an empty array because the callback returns true for directories.

What do you see instead?

The callback receives a Dirent for the ambient process.cwd() path instead:

{
  "processCwd": "/tmp/.../ambient",
  "globCwd": "/tmp/.../root",
  "seen": [
    {
      "name": "a",
      "parentPath": ".",
      "isDirectory": false,
      "isFile": true
    },
    {
      "name": "real.txt",
      "parentPath": "/tmp/.../root/a",
      "isDirectory": false,
      "isFile": true
    }
  ],
  "result": [
    {
      "name": "a",
      "parentPath": "/tmp/.../root",
      "isDirectory": true,
      "isFile": false
    },
    {
      "name": "real.txt",
      "parentPath": "/tmp/.../root/a",
      "isDirectory": false,
      "isFile": true
    }
  ]
}

So the root a entry is not excluded even though the callback logic is meant to exclude directories.

Additional information

This looks like a sync-only regression in the root-path exclude handling added for #56260 / #57420.

In lib/internal/fs/glob.js, #addSubpattern() computes const fullpath = resolve(this.#root, path), but in the withFileTypes + exclude branch it does:

const stat = this.#cache.statSync(path);

That appears to stat a path relative to process.cwd() instead of options.cwd. The async path already uses await this.#cache.stat(fullpath).

Lingua principale
JavaScript
Stelle
122k
Fork
37.4k
Merge medio
4g 3h
PR unite (30g)
279

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di nodejs/node

Tutte le issue di nodejs/node

Issue simili

Altre issue su JavaScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.