Repository navigation
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
aduh95
left a comment
There was a problem hiding this comment.
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.
commented
Jan 29, 2022
|
Sure, added to This PR makes separation between |
c5da4e9 to
b479182
Compare
b479182 to
c5e0583
Compare
commented
Jan 30, 2022
|
cc @nodejs/tsc since it's a semver-major |
commented
Feb 5, 2022
commented
Feb 7, 2022
commented
Feb 8, 2022
|
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 |
commented
Feb 13, 2022
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 |
commented
Feb 14, 2022
|
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
Refs: #41666
Potentially breaking changes.An attempt to implement "named parameters" for filehandle.write (Promises API) and fs.writeSync (Synchronous API).ArrayBufferViewandstringforms 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""+objThis 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=>optionsSynchronous API:
buffer, offset, length, position=>buffer, optionsAt 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
lengthis 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
lengthand tests.Edit [2022-04-04]:
This PR doesn't add new feature anymore (847749f)
Optional params will be added in separate PR.