Skip to content

feat: handle fs.F_OK, fs.R_OK, fs.W_OK, fs.X_OK depreciation #130

@AugustinMauroy

Description

@AugustinMauroy

Description

Since fs.F_OK, fs.R_OK, fs.W_OK, and fs.X_OK are deprecated (DEP0176) and have reached End-of-Life status, we should provide a codemod to replace them.

  • The codemod should replace all instances of fs.F_OK, fs.R_OK, fs.W_OK, and fs.X_OK with fs.constants.F_OK, fs.constants.R_OK, fs.constants.W_OK, and fs.constants.X_OK respectively.
  • The codemod should handle both CommonJS and ESM import patterns.
  • The codemod should work with destructured imports and namespace imports.
  • The codemod should also handle fs.promises.constants as an alternative replacement.

Additional Information

Note that fs.F_OK, fs.R_OK, fs.W_OK, and fs.X_OK getters exposed directly on node:fs were removed in Node.js v25.0.0. These constants were deprecated because they were exposed at the module level for convenience, but the proper way to access them is through fs.constants or fs.promises.constants which provides better organization and consistency.

The functionality is identical, but accessing these constants through the constants object is the standard and supported way.

Examples

Case 1: Direct access with namespace import

Before:

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

fs.access('/path/to/file', fs.F_OK, callback);
fs.access('/path/to/file', fs.R_OK | fs.W_OK, callback);

After:

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

fs.access('/path/to/file', fs.constants.F_OK, callback);
fs.access('/path/to/file', fs.constants.R_OK | fs.constants.W_OK, callback);

Case 2: ESM namespace import

Before:

import * as fs from 'node:fs';

fs.access('/path/to/file', fs.F_OK, callback);
fs.access('/path/to/file', fs.X_OK, callback);

After:

import * as fs from 'node:fs';

fs.access('/path/to/file', fs.constants.F_OK, callback);
fs.access('/path/to/file', fs.constants.X_OK, callback);

Case 3: Destructured import

Before:

const { access, F_OK, R_OK, W_OK } = require('node:fs');

access('/path/to/file', F_OK, callback);
access('/path/to/file', R_OK | W_OK, callback);

After:

const { access, constants } = require('node:fs');

access('/path/to/file', constants.F_OK, callback);
access('/path/to/file', constants.R_OK | constants.W_OK, callback);

Case 4: ESM destructured import

Before:

import { access, F_OK, R_OK, W_OK, X_OK } from 'node:fs';

access('/path/to/file', F_OK, callback);
access('/path/to/file', R_OK | W_OK | X_OK, callback);

After:

import { access, constants } from 'node:fs';

access('/path/to/file', constants.F_OK, callback);
access('/path/to/file', constants.R_OK | constants.W_OK | constants.X_OK, callback);

Case 5: Mixed usage patterns

Before:

const { accessSync, F_OK, R_OK } = require('node:fs');
const fs = require('node:fs');

accessSync('/path/to/file', F_OK);
fs.access('/path/to/file', fs.W_OK | R_OK, callback);

After:

const { accessSync, constants } = require('node:fs');
const fs = require('node:fs');

accessSync('/path/to/file', constants.F_OK);
fs.access('/path/to/file', fs.constants.W_OK | constants.R_OK, callback);

Case 6: Using fs.promises.constants alternative

Before:

import { promises as fsPromises, F_OK, R_OK } from 'node:fs';

await fsPromises.access('/path/to/file', F_OK);

After:

import { promises as fsPromises } from 'node:fs';

await fsPromises.access('/path/to/file', fsPromises.constants.F_OK);

Case 7: Complex expressions

Before:

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

const mode = fs.R_OK | fs.W_OK;
if (condition) {
  fs.accessSync('/path/to/file', fs.F_OK);
}

After:

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

const mode = fs.constants.R_OK | fs.constants.W_OK;
if (condition) {
  fs.accessSync('/path/to/file', fs.constants.F_OK);
}

Case 8: Variable assignments

Before:

import { F_OK, R_OK, W_OK, X_OK } from 'node:fs';

const readable = R_OK;
const writable = W_OK;
const executable = X_OK;
const exists = F_OK;

After:

import { constants } from 'node:fs';

const readable = constants.R_OK;
const writable = constants.W_OK;
const executable = constants.X_OK;
const exists = constants.F_OK;

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