-
Notifications
You must be signed in to change notification settings - Fork 29.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fs: fix write methods param validation and docs #41677
Conversation
@nodejs/fs |
b9cf3e0
to
5037e54
Compare
Added tests, covered somewhat related edge cases in existing tests, rebased on master branch. |
bce6121
to
ac0e126
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add entries to the changes
list in the YAML comment to say that objects with an own toString
method are no longer supported with this change.
Sure, added to This PR makes separation between |
c5da4e9
to
b479182
Compare
b479182
to
c5e0583
Compare
cc @nodejs/tsc since it's a semver-major |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
I would like to hear any thoughts about Aside from issues mentioned earlier, the current implicit object stringifying has two more.
Some ugly code showcasing the problematic behaviour: import * as fs from 'fs';
const OUTFILE = '/tmp/fswriteobj';
function TstCtor(data) {
this._data = data;
this._json = JSON.stringify(data);
this[Symbol.toPrimitive] = () => this._data?.length;
this.toString = () => this._json;
}
class TstClass {
[Symbol.toPrimitive]() { return 'P' };
toString() { return 'S' };
}
const tst1 = {toString: () => tst1.undefinedProperty};
const tst2 = {toString: () => 'S', [Symbol.toPrimitive]: () => 'P'};
const tst3 = new String('A');
const tst4 = new String('A');
tst4[Symbol.toPrimitive] = () => 'P';
const tst5 = new String('A');
tst5.toString = () => 'S';
const tst6 = new String('A');
tst6[Symbol.toPrimitive] = () => 'P';
tst6.toString = () => 'S';
const tst7 = new TstCtor(["one","two"]);
const tst8 = new TstClass();
const tst9 = new TstClass();
tst9.toString = () => 'S';
// "undefined", "P", TypeError, TypeError, "S", "P", "2", TypeError, "P"
fs.open(OUTFILE, 'w', (err, fd) => {
for (const writeMe of [tst1,tst2,tst3,tst4,tst5,tst6,tst7,tst8,tst9]) {
try {
fs.write(fd, writeMe, (err, written, string) => console.log(typeof string));
} catch(e) {
console.error(e.name);
}
}
}); It also shows that toString defined in class doesn't allow typecasting here, since it's not an ownProperty even on direct class instance. Of course, the second issue can be fixed in docs; and there are several trivial ways to "fix" first one, e.g. by - const str = String(buffer);
+ const str = String(buffer.toString()); but I don't see any really good solution. It's either breaking changes in API anyway, or documenting on how and why Am I missing something, or it deserves to become deprecated for now, in favor of |
Good catch, I think this have been overlooked in the original implementation (own A deprecation also makes sense to me, I think asking folks to wrap their object in |
Thanks; I'm leaning towards deprecation for the following reasons:
Thereby, I'd rather not fix it and definitely not backport, unless there's some software that actually relies on this feature, actually suffers from "bug" in it, and for some reason can't be fixed by explicit typecast. Since this PR is semver-major and code-wise changes will be the same as for promises and sync versions, could it be done there? Or I should open a standalone deprecation PR? |
c5e0583
to
74d6d47
Compare
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: #34993 PR-URL: #41677 Refs: #41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
This should not be landed in v17.x, ref: #42613 (comment) |
@juanarbol that’s incorrect, this should land on v17.x. |
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: nodejs#34993 PR-URL: nodejs#41677 Refs: nodejs#41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: #34993 PR-URL: #41677 Backport-PR-URL: #42631 Refs: #41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
This also affects `fs.writeFile`, `fs.appendFile`, and `fs.appendFileSync` Refs: #41677 PR-URL: #42149 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]>
This also affects `fs.writeFile`, `fs.appendFile`, and `fs.appendFileSync` Refs: #41677 PR-URL: #42149 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]>
This also affects `fs.writeFile`, `fs.appendFile`, and `fs.appendFileSync` Refs: #41677 PR-URL: #42149 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]>
This also affects `fs.writeFile`, `fs.appendFile`, and `fs.appendFileSync` Refs: #41677 PR-URL: #42149 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]>
This also affects `fs.writeFile`, `fs.appendFile`, and `fs.appendFileSync` Refs: nodejs#41677 PR-URL: nodejs#42149 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]>
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: nodejs#34993 PR-URL: nodejs#41677 Refs: nodejs#41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: #34993 PR-URL: #41677 Refs: #41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]> Backport-PR-URL: #42603
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: #34993 PR-URL: #41677 Refs: #41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: #34993 PR-URL: #41677 Refs: #41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: #34993 PR-URL: #41677 Refs: #41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: #34993 PR-URL: #41677 Refs: #41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
The FS docs wrongfully indicated support for passing object with an own `toString` function property to `FileHandle.prototype.appendFile`, `FileHandle.prototype.writeFile`, `FileHandle.prototype.write`, `fsPromises.writeFile`, and `fs.writeSync`. This commit fixes that, and adds some test to ensure the actual behavior is aligned with the docs. It also fixes a bug that makes the process crash if a non-buffer object was passed to `FileHandle.prototype.write`. Refs: nodejs/node#34993 PR-URL: nodejs/node#41677 Refs: nodejs/node#41666 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Refs: #41666
Potentially breaking changes.An attempt to implement "named parameters" for filehandle.write (Promises API) and fs.writeSync (Synchronous API).ArrayBufferView
andstring
forms in documentation.Current documentation, also including fs.write (Callback API), described behaviour for string|Object argument in [buffer, offset, length, position] version.
This functionality doesn't help with most cases, when an object inherits .toString from its prototype
This functionality doesn't work with Symbol.toPrimitive
This functionality is easily replaceable with
obj.toString()
,String(obj)
or""+obj
This functionality in Promises and Synchronous APIs seems to be broken for a long time
Function signatures are chosen to match their .read counterparts.Promises API:
buffer, offset, length, position
=>options
Synchronous API:
buffer, offset, length, position
=>buffer, options
At this point, these changes should not break any existing working code.
For code trying to use documented feature of accepting objects with explicit .toString, outcome changes from abortion to exception.
Any feedback is appreciated.
Edit [2022-02-26]:Soft-blocked by #42128
Default value of
length
is being changed for reading methods: it should be aligned for writing methods, and it would require adjustments in tests here.Edit [2022-02-27]:doneWIP, adjusting default
length
and tests.Edit [2022-04-04]:
This PR doesn't add new feature anymore (847749f)
Optional params will be added in separate PR.