Open slavafomin opened 1 year ago
You should certainly be able to detect this feature, since it’s API and not syntax.
You should certainly be able to detect this feature, since it’s API and not syntax.
Could you recommend an approach to do this?
Maybe I don't see something obvious here, but as far as I know JS doesn't have a reflection API that will allow me to examine the number of arguments of the passed callback function. Of course I can turn the function to a string and then parse it's code in order to detect whether it has a third argument, but it looks pretty brittle. And this definitely won't work with the arguments
.
In general, the detection could only happen when the user accesses the context.source
or context.keys
properties of the reviver function argument, but when this happens it's already too late to change the underlying parser implementation.
The only approach I see is that we can use JSON.parse
initially and then discard the parsed result and re-parse the content using our custom implementation when we detect access to the context
argument. This will lead to parsing the JSON document two times in a worst-case scenario and we will need to count the number of callbacks that was already fired in order to not call reviver multiple times for the same property.
This option is viable, but looks too hacky and not optimal to me.
@gibson042 @mathiasbynens @ljharb could you please take a look at the implementation or at least at the API of the library? There are also some tests for this proposal. I just need to know if I got the proposal correctly. Thanks in advance!
@slavafomin you wouldn't need to do it every time - you just do it once with a known source string, and cache the result forever. For example, from the readme, JSON.stringify({ tooBigForNumber }, bigIntToRawJSON) === '{"tooBigForNumber":9007199254740993}'
will be true
when the feature is supported.
@slavafomin you wouldn't need to do it every time - you just do it once with a known source string, and cache the result forever. For example, from the readme,
JSON.stringify({ tooBigForNumber }, bigIntToRawJSON) === '{"tooBigForNumber":9007199254740993}'
will betrue
when the feature is supported.
I'm not sure I follow, could you elaborate please? What exactly should we cache?
the boolean result of that comparison - either true
if it's supported, or false
if it's not.
Maybe I don't see something obvious here, but as far as I know JS doesn't have a reflection API that will allow me to examine the number of arguments of the passed callback function. Of course I can turn the function to a string and then parse it's code in order to detect whether it has a third argument, but it looks pretty brittle. And this definitely won't work with the arguments.
Does https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length solve the problem?
Maybe I don't see something obvious here, but as far as I know JS doesn't have a reflection API that will allow me to examine the number of arguments of the passed callback function. Of course I can turn the function to a string and then parse it's code in order to detect whether it has a third argument, but it looks pretty brittle. And this definitely won't work with the arguments.
Does https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length solve the problem?
Didn't know that, thanks for mentioning! I'm gonna test it out.
Does https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length solve the problem?
By the way it won't work with arguments
, but I think it's a pretty rare use case so we can ignore (document) it for now.
Thanks to the @HolgerJeromin suggestion, I've implemented a proper polyfill. Here's the usage details. And here's the implementation.
I've already released a beta-version of the package that can be used for testing: @ton.js/json-parse-polyfill@beta
.
Still, will be very happy for implementation review!
You can use this code to detect if the new proposal is implemented:
let parse = function parse(string, callback) {
callback(1, 2, { source: 3 });
};
function detect() {
return new Promise(resolve => {
// use JSON.parse here
parse('"x"', function(key, value, x) {
resolve(typeof x !== 'undefined');
});
});
}
const supported = await detect();
console.log({supported: await detect()});
parse = function parse(string, callback) {
callback(1, 2);
};
console.log({supported: await detect()});
the parse function is JSON.parse mock that executes the receiver with an extra argument that is tested.
EDIT: And since the JSON.parse is not async you can use this version:
function detect() {
let result;
JSON.parse('"x"', function(key, value, x) {
result = typeof x !== 'undefined';
});
return result;
}
to whom it might concern, another ponyfill landed in ungap: https://github.com/ungap/raw-json
Hello!
Thank you for this proposal and your hard work!
While waiting for the proposal to be generally available, I've implemented a custom JSON parser that is future-compatible with the proposal. It doesn't look feasible to make it a proper polyfill, considering that JS implementation will probably be slower and we can't detect new features usage, but it's a ponyfill that can be used today where needed.
I'm not sure that I've implemented all the features correctly, it's not that easy to follow the standard, but all the serialization examples should work correctly. I will be very grateful if someone could review the implementation.
Thanks!