nodejs / nodejs/userland-migrations
`fs.write()` and `fs.writeFileSync()` coercion to string
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 85
- Forks
- 55
- Avg merge
- 3d 11h
- Merged PRs (30d)
- 9
Description
Description
Since implicit coercion of objects in fs.write() and fs.writeFileSync() is deprecated (DEP0162) and has reached End-of-Life status in Node.js v19.0.0, we should provide a codemod to replace them.
- The codemod should convert objects with
toString()method to primitive strings before passing to fs write functions. - The codemod should handle
fs.write(),fs.writeFile(),fs.appendFile(),fs.writeFileSync(), andfs.appendFileSync(). - The codemod should detect objects being passed as the data parameter.
- The codemod should add explicit
.toString()calls orString()conversion.
Additional Information
Note that in Node.js v19.0.0, implicit coercion of objects with own toString property passed as the second parameter (data) in fs write operations now throws an error. This was deprecated because the implicit conversion could lead to unexpected behavior and made the code less explicit.
Instead of relying on implicit coercion, developers should explicitly convert objects to strings using .toString(), String(), or template literals.
Examples
Example 1: Object in fs.writeFileSync()
Before:
const fs = require("node:fs");
const data = { toString: () => "file content" };
fs.writeFileSync("file.txt", data);
After:
const fs = require("node:fs");
const data = { toString: () => "file content" };
fs.writeFileSync("file.txt", data.toString());
Example 2: Object in fs.writeFile()
Before:
const fs = require("node:fs");
const obj = { toString: () => "content" };
fs.writeFile("file.txt", obj, (err) => {
if (err) throw err;
});
After:
const fs = require("node:fs");
const obj = { toString: () => "content" };
fs.writeFile("file.txt", obj.toString(), (err) => {
if (err) throw err;
});
Example 3: Object in fs.appendFileSync()
Before:
const fs = require("node:fs");
const data = { toString: () => "appended data" };
fs.appendFileSync("file.txt", data);
After:
const fs = require("node:fs");
const data = { toString: () => "appended data" };
fs.appendFileSync("file.txt", data.toString());
Example 4: Object in fs.appendFile()
Before:
const fs = require("node:fs");
const content = { toString: () => "more content" };
fs.appendFile("file.txt", content, (err) => {
if (err) throw err;
});
After:
const fs = require("node:fs");
const content = { toString: () => "more content" };
fs.appendFile("file.txt", content.toString(), (err) => {
if (err) throw err;
});
Example 5: Object in fs.write()
Before:
const fs = require("node:fs");
const fd = fs.openSync("file.txt", "w");
const data = { toString: () => "buffer content" };
fs.write(fd, data, (err) => {
if (err) throw err;
fs.closeSync(fd);
});
After:
const fs = require("node:fs");
const fd = fs.openSync("file.txt", "w");
const data = { toString: () => "buffer content" };
fs.write(fd, data.toString(), (err) => {
if (err) throw err;
fs.closeSync(fd);
});
Example 6: Using String() conversion
Before:
const fs = require("node:fs");
const myObj = {
value: 42,
toString() {
return `Value: ${this.value}`;
}
};
fs.writeFileSync("output.txt", myObj);
After:
const fs = require("node:fs");
const myObj = {
value: 42,
toString() {
return `Value: ${this.value}`;
}
};
fs.writeFileSync("output.txt", String(myObj));
Example 7: ESM with promises API
Before:
import { writeFile } from "node:fs/promises";
const data = { toString: () => "async content" };
await writeFile("file.txt", data);
After:
import { writeFile } from "node:fs/promises";
const data = { toString: () => "async content" };
await writeFile("file.txt", data.toString());
Example 8: Valid types (no change needed)
Before:
const fs = require("node:fs");
// These are all valid and don't need changes
fs.writeFileSync("file1.txt", "string");
fs.writeFileSync("file2.txt", Buffer.from("buffer"));
fs.writeFileSync("file3.txt", new Uint8Array([1, 2, 3]));
After:
const fs = require("node:fs");
// These are all valid and don't need changes
fs.writeFileSync("file1.txt", "string");
fs.writeFileSync("file2.txt", Buffer.from("buffer"));
fs.writeFileSync("file3.txt", new Uint8Array([1, 2, 3]));
Refs
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The payload names no repository files, tests, or codemod entry point; start by locating the existing migration framework and its coverage for Node.js fs APIs. Use the listed fs methods, the node:fs/promises example, and the valid Buffer and Uint8Array cases to define coverage, then verify object coercion changes without altering valid types.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js, typescript
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100