| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
@guybedford Feel free to take a look at this |
Sorry, something went wrong.
There was a problem hiding this comment.
Can you please clarify if any of the changes here are major / breaking changes?
//cc @nodejs/repl for more reviewers.
Sorry, something went wrong.
|
I'd like to add the output of debug to my test assertions, so I confirm the queue flow is happening as expected, but didn't see any other repl test that is asserting debug output (and using NODE_DEBUG=repl before calling the tests makes the output end up in my terminal instead of repl output stream), any ideas how I can do it? |
Sorry, something went wrong.
|
@ejose19 I'm not aware of any debug stream testing, but there might be some examples in the existing tests directory to be found. Alternatively setting up something custom could be worthwhile unless someone else can clarify further here. |
Sorry, something went wrong.
|
@guybedford I had to replace the original debuglog function before importing repl in order to access debug data. That should be enough for this test. |
Sorry, something went wrong.
|
@ejose19 if we're doing a major change here anyway, should we also support eval returning a Promise? Or is the callback definitely necessary to get the correct timings? |
Sorry, something went wrong.
|
@guybedford That would require a major overhaul in the tests, since most of them expect the output right after writing the input, which is the case for sync code. But if eval is async, code execution (and output) would be done in the next iteration. So even if using async eval would be ideal, it's outside the scope of this PR due the large amount of changes. |
Sorry, something went wrong.
|
@ejose19 what I mean is branching the API on sync / async handling with: eval: () => Promise | undefinedwhere the undefined case is treated as sync, and the promise case is treated as the async situation, for example rather than enforcing the callback. That's not the exact approach but along those lines I mean. |
Sorry, something went wrong.
|
@guybedford you mean something like this? const evalResult = self.eval(evalCmd, self.context, getREPLResourceName(), finish);
if (evalResult !== undefined) {
if (!(evalResult instanceof Promise)) {
self._domain.emit('error', 'eval must return "undefined" or a "Promise"');
return;
}
(async () => {
const { error, result } = await evalResult;
finish(error, result);
})();
} |
Sorry, something went wrong.
|
Yes that seems like the sort of approach if you agree it could make sense. Would this also allow this PR to be done in a backwards compatible way perhaps? Perhaps we should consider being more lenient on the return value to be safe in that case? Either way wrt the validation could work for me though. |
Sorry, something went wrong.
|
I don't think it can be made backward compatible, we can't assume undefined = "sync code", as it's not even the case for node own defaultEval (notice how the promise is not returned): Lines 606 to 623 in 44e3822 If other projects based their eval implementation following node defaultEval, then undefined can also mean promise handling. Ideally, self.on('line') should be refactored into for await (const cmd of self), so line processing is guaranteed to be one at a time without needing a queue, and eval should be made a Promise resolving to { err?: any, result?: any }, to avoid the need of a callback completely and making the implementation more direct. But that comes with all the tests refactor and the "breaking" change of writing to stdin will no longer yield a response in the current tick. |
Sorry, something went wrong.
|
@ejose19 I guess I'm still not clear on how the callback can be optional currently. But if the current eval doesn't return a value, then allowing the current eval to return a promise would be a backwards-compatible extension. Then allowing that promise to be a completion based callback that fits the requirements you needed for the async callback could also be a way to possible shoehorn this feature in a backwards compatible way (separate to the explicit callback mechanism). Again I'm not super clear on the details of this code, so fill me in where I'm wrong :) |
Sorry, something went wrong.
@guybedford If something like this is added to the PR, then eval must either:
For any code that is not returning a Promise and neither was executing the callback, it WILL be a breaking change since new lines won't be allowed to be processed (you noticed that it was necessary to execute the callback on tests, and probably some consumers have a similar implementation). So what I mean is, while we can improve the "handling" of eval supporting both undefined (but executed/will execute callback) and Promise as return values for eval, I don't see how it can be backward compatible for current code that does neither. |
Sorry, something went wrong.
|
So because the invariant of per-line processing requires all eval implementations to conform, there's no middle ground here on creating a backwards compatible subset, got it. In that case moving ahead with this as-is seems fine to me. |
Sorry, something went wrong.
|
One other question - what will be the outcome for eval implementations that do not call the callback? Will it just stall? |
Sorry, something went wrong.
Correct, for most commands that will be the outcome, unless other event resets the processing property to false (like domain errors or SIGINT) |
Sorry, something went wrong.
|
@ejose19 another option could be to check the function length of the eval function to see if its length includes the callback argument position. If not included it could be assumed to be "sync". |
Sorry, something went wrong.
|
@guybedford Ok, that's an interesting approach, but it's enough for this to be considered non breaking? What about consumers that defined the argument but never called it? |
Sorry, something went wrong.
|
I tried with that, and it seems this line: Line 632 in 44e3822 makes the function to have a different length than the original (0 vs 4 for defaultEval), so even if we compare against eval_ directly, I don't think it's safe to "assume" the consumer won't execute the callback based on that alone, in case they're doing something similar to node before passing the function to repl creation. |
Sorry, something went wrong.
|
Ok, thanks for hearing me out on these questions, agreed the major is best then with the callback being enforced. |
Sorry, something went wrong.
Sorry, something went wrong.
Sorry, something went wrong.
|
The CI failures here need to be investigated. They appear they might b relevant to the change |
Sorry, something went wrong.
Sorry, something went wrong.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Fixes: #39387