Skip to content

feat: handle dirent.path depreciation #131

@AugustinMauroy

Description

@AugustinMauroy

Description

Since dirent.path is deprecated (DEP0178) and has reached End-of-Life status, we should provide a codemod to replace it.

  • The codemod should replace all instances of dirent.path with dirent.parentPath.
  • The codemod should handle different usage patterns including property access, destructuring, and method chaining.
  • The codemod should work with various fs operations that return fs.Dirent objects.
  • The codemod should preserve existing functionality while updating to the supported API.

Additional Information

Note that dirent.path was removed in Node.js v24.0.0 due to its lack of consistency across release lines. Users should use dirent.parentPath instead. The path property was deprecated because it provided inconsistent behavior and could be confusing when working with directory entries.

The dirent.parentPath property provides the same functionality but with clearer semantics - it represents the path to the parent directory of the file that the fs.Dirent object refers to.

Examples

Case 1: Basic property access

Before:

const { readdir } = require('node:fs/promises');

const entries = await readdir('/some/path', { withFileTypes: true });
for (const dirent of entries) {
  console.log(dirent.path);
}

After:

const { readdir } = require('node:fs/promises');

const entries = await readdir('/some/path', { withFileTypes: true });
for (const dirent of entries) {
  console.log(dirent.parentPath);
}

Case 2: ESM import with property access

Before:

import { readdir } from 'node:fs/promises';

const entries = await readdir('./directory', { withFileTypes: true });
entries.forEach(dirent => {
  const fullPath = `${dirent.path}/${dirent.name}`;
  console.log(fullPath);
});

After:

import { readdir } from 'node:fs/promises';

const entries = await readdir('./directory', { withFileTypes: true });
entries.forEach(dirent => {
  const fullPath = `${dirent.parentPath}/${dirent.name}`;
  console.log(fullPath);
});

Case 3: Destructuring assignment

Before:

const fs = require('node:fs');

fs.readdir('/path', { withFileTypes: true }, (err, dirents) => {
  if (err) throw err;
  
  dirents.forEach(({ name, path, isDirectory }) => {
    console.log(`${name} in ${path}`);
  });
});

After:

const fs = require('node:fs');

fs.readdir('/path', { withFileTypes: true }, (err, dirents) => {
  if (err) throw err;
  
  dirents.forEach(({ name, parentPath, isDirectory }) => {
    console.log(`${name} in ${parentPath}`);
  });
});

Case 4: Using with fs.opendir

Before:

import { opendir } from 'node:fs/promises';

const dir = await opendir('./');
for await (const dirent of dir) {
  console.log(`Found ${dirent.name} in ${dirent.path}`);
}

After:

import { opendir } from 'node:fs/promises';

const dir = await opendir('./');
for await (const dirent of dir) {
  console.log(`Found ${dirent.name} in ${dirent.parentPath}`);
}

Case 5: Conditional access

Before:

const { readdirSync } = require('node:fs');

const entries = readdirSync('./', { withFileTypes: true });
const files = entries.filter(dirent => {
  return dirent.isFile() && dirent.path.includes('src');
});

After:

const { readdirSync } = require('node:fs');

const entries = readdirSync('./', { withFileTypes: true });
const files = entries.filter(dirent => {
  return dirent.isFile() && dirent.parentPath.includes('src');
});

Case 6: Building full file paths

Before:

import { join } from 'node:path';
import { readdir } from 'node:fs/promises';

async function getFilePaths(directory) {
  const dirents = await readdir(directory, { withFileTypes: true });
  return dirents
    .filter(dirent => dirent.isFile())
    .map(dirent => join(dirent.path, dirent.name));
}

After:

import { join } from 'node:path';
import { readdir } from 'node:fs/promises';

async function getFilePaths(directory) {
  const dirents = await readdir(directory, { withFileTypes: true });
  return dirents
    .filter(dirent => dirent.isFile())
    .map(dirent => join(dirent.parentPath, dirent.name));
}

Case 7: Complex object manipulation

Before:

const fs = require('node:fs');

function processDirectory(path) {
  const entries = fs.readdirSync(path, { withFileTypes: true });
  
  return entries.map(dirent => ({
    name: dirent.name,
    directory: dirent.path,
    type: dirent.isDirectory() ? 'dir' : 'file',
    fullPath: `${dirent.path}/${dirent.name}`
  }));
}

After:

const fs = require('node:fs');

function processDirectory(path) {
  const entries = fs.readdirSync(path, { withFileTypes: true });
  
  return entries.map(dirent => ({
    name: dirent.name,
    directory: dirent.parentPath,
    type: dirent.isDirectory() ? 'dir' : 'file',
    fullPath: `${dirent.parentPath}/${dirent.name}`
  }));
}

Case 8: Recursive directory traversal

Before:

import { readdir } from 'node:fs/promises';
import { join } from 'node:path';

async function walkDirectory(dirPath) {
  const dirents = await readdir(dirPath, { withFileTypes: true });
  
  for (const dirent of dirents) {
    const currentPath = join(dirent.path, dirent.name);
    
    if (dirent.isDirectory()) {
      await walkDirectory(currentPath);
    } else {
      console.log(`File: ${currentPath}`);
    }
  }
}

After:

import { readdir } from 'node:fs/promises';
import { join } from 'node:path';

async function walkDirectory(dirPath) {
  const dirents = await readdir(dirPath, { withFileTypes: true });
  
  for (const dirent of dirents) {
    const currentPath = join(dirent.parentPath, dirent.name);
    
    if (dirent.isDirectory()) {
      await walkDirectory(currentPath);
    } else {
      console.log(`File: ${currentPath}`);
    }
  }
}

Refs

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    🏗 In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions