Skip to content

Commit df518fc

Browse files
authored
feat(fs-access-mode-constants): introduce (#152)
1 parent f55edef commit df518fc

22 files changed

+258
-9
lines changed

package-lock.json

Lines changed: 15 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# `fs.F_OK`, `fs.R_OK`, `fs.W_OK`, `fs.X_OK` DEP0176
2+
3+
Handle DEP0176 via transforming imports of `fs.F_OK`, `fs.R_OK`, `fs.W_OK`, `fs.X_OK` from the root `fs` module to `fs.constants`.
4+
5+
See [DEP0176](https://nodejs.org/api/deprecations.html#dep0176-fsf_ok-fsr_ok-fsw_ok-fsx_ok)
6+
7+
## Example
8+
9+
**Before:**
10+
```js
11+
const fs = require('node:fs');
12+
13+
fs.access('/path/to/file', fs.F_OK, callback);
14+
fs.access('/path/to/file', fs.R_OK | fs.W_OK, callback);
15+
```
16+
17+
**After:**
18+
```js
19+
const fs = require('node:fs');
20+
21+
fs.access('/path/to/file', fs.constants.F_OK, callback);
22+
fs.access('/path/to/file', fs.constants.R_OK | fs.constants.W_OK, callback);
23+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
schema_version: "1.0"
2+
name: "@nodejs/fs-access-mode-constants"
3+
version: "1.0.0"
4+
description: Handle DEP0176 via transforming imports of `fs.F_OK`, `fs.R_OK`, `fs.W_OK`, `fs.X_OK` from the root `fs` module to `fs.constants`.
5+
author: nekojanai (Jana)
6+
license: MIT
7+
workflow: workflow.yaml
8+
category: migration
9+
10+
targets:
11+
languages:
12+
- javascript
13+
- typescript
14+
15+
keywords:
16+
- transformation
17+
- migration
18+
19+
registry:
20+
access: public
21+
visibility: public
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@nodejs/fs-access-mode-constants",
3+
"version": "1.0.0",
4+
"description": "Handle DEP0176 via transforming imports of `fs.F_OK`, `fs.R_OK`, `fs.W_OK`, `fs.X_OK` from the root `fs` module to `fs.constants`.",
5+
"type": "module",
6+
"scripts": {
7+
"test": "npx codemod jssg test -l typescript ./src/workflow.ts ./"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/nodejs/userland-migrations.git",
12+
"directory": "recipes/fs-access-mode-constants",
13+
"bugs": "https://github.com/nodejs/userland-migrations/issues"
14+
},
15+
"author": "nekojanai (Jana)",
16+
"license": "MIT",
17+
"homepage": "https://github.com/nodejs/userland-migrations/blob/main/recipes/fs-access-mode-constants/README.md",
18+
"dependencies": {
19+
"@nodejs/codemod-utils": "*"
20+
},
21+
"devDependencies": {
22+
"@codemod.com/jssg-types": "^1.0.3"
23+
}
24+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import type { Edit, SgRoot } from "@codemod.com/jssg-types/main";
2+
import { getNodeRequireCalls } from "@nodejs/codemod-utils/ast-grep/require-call";
3+
import type Js from "@codemod.com/jssg-types/langs/javascript";
4+
import { getNodeImportStatements } from "@nodejs/codemod-utils/ast-grep/import-statement";
5+
6+
export default function tranform(root: SgRoot<Js>): string | null {
7+
const rootNode = root.root();
8+
const edits: Edit[] = [];
9+
10+
// @ts-expect-error - ast-grep types are not fully compatible with JSSG types
11+
const requireStatements = getNodeRequireCalls(root, "fs");
12+
13+
for (const statement of requireStatements) {
14+
const objectPattern = statement.find({
15+
rule:
16+
{ kind: 'object_pattern' },
17+
});
18+
19+
if (objectPattern) {
20+
let objPatArr = objectPattern.findAll({
21+
rule:
22+
{ kind: 'shorthand_property_identifier_pattern' },
23+
}).map((v) => v.text());
24+
objPatArr = objPatArr.filter((v) => !['F_OK', 'R_OK', 'W_OK', 'X_OK'].includes(v));
25+
objPatArr.push('constants');
26+
edits.push(objectPattern.replace(`{ ${objPatArr.join(', ')} }`));
27+
};
28+
}
29+
30+
// @ts-expect-error - ast-grep types are not fully compatible with JSSG types
31+
const importStatements = getNodeImportStatements(root, "fs");
32+
let promisesImportName = '';
33+
34+
for (const statement of importStatements) {
35+
const objectPattern = statement.find({
36+
rule:
37+
{ kind: 'named_imports' },
38+
});
39+
40+
if (objectPattern) {
41+
let objPatArr = objectPattern.findAll({
42+
rule:
43+
{ kind: 'import_specifier' },
44+
}).map((v) => v.text());
45+
objPatArr = objPatArr.filter((v) => !['F_OK', 'R_OK', 'W_OK', 'X_OK'].includes(v));
46+
const promisesImport = objPatArr.find((v) => v.startsWith('promises'));
47+
if (promisesImport) {
48+
if (promisesImport.includes('as')) {
49+
const m = promisesImport.matchAll((/promises as (\w+)/g));
50+
m.forEach((v) => promisesImportName = v[1] ?? 'promises');
51+
} else {
52+
promisesImportName = promisesImport;
53+
}
54+
promisesImportName = `${promisesImportName}.`
55+
} else {
56+
objPatArr.push('constants');
57+
}
58+
edits.push(objectPattern.replace(`{ ${objPatArr.join(', ')} }`));
59+
}
60+
}
61+
62+
for (const _OK of ['F_OK', 'R_OK', 'W_OK', 'X_OK']) {
63+
for (const [prefix, replacement] of [['fs.', 'fs.constants.'], ['', `${promisesImportName ? promisesImportName : ''}constants.`]]) {
64+
const patterns = rootNode.findAll({
65+
rule: {
66+
pattern: `${prefix}${_OK}`
67+
}
68+
});
69+
for (const pattern of patterns) {
70+
edits.push(pattern.replace(`${replacement}${_OK}`));
71+
}
72+
}
73+
}
74+
75+
return rootNode.commitEdits(edits);
76+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const fs = require('node:fs');
2+
3+
fs.access('/path/to/file', fs.constants.F_OK, callback);
4+
fs.access('/path/to/file', fs.constants.R_OK | fs.constants.W_OK, callback);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import * as fs from 'node:fs';
2+
3+
fs.access('/path/to/file', fs.constants.F_OK, callback);
4+
fs.access('/path/to/file', fs.constants.X_OK, callback);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const { access, constants } = require('node:fs');
2+
3+
access('/path/to/file', constants.F_OK, callback);
4+
access('/path/to/file', constants.R_OK | constants.W_OK, callback);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { access, constants } from 'node:fs';
2+
3+
access('/path/to/file', constants.F_OK, callback);
4+
access('/path/to/file', constants.R_OK | constants.W_OK | constants.X_OK, callback);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const { accessSync, constants } = require('node:fs');
2+
const fs = require('node:fs');
3+
4+
accessSync('/path/to/file', constants.F_OK);
5+
fs.access('/path/to/file', fs.constants.W_OK | constants.R_OK, callback);

0 commit comments

Comments
 (0)