07:39
<ljharb>
they're working on a new config system, and it supports ESM, and thus it has to be async
07:39
<ljharb>
so i don't see why they'd be opposed to rules working that way
07:43
<bakkot>
https://github.com/eslint/eslint/issues/15394#issuecomment-989410995
07:43
<bakkot>
¯\_(ツ)_/¯
07:44
<ljharb>
i read your gensync thing and i still really don't understand the point. if you already have both a sync and async version, then sure, and if you only have a sync version, then it's pretty trivial to wrap that in an async function, but if you only have an async version then how can you make it sync?
07:45
<bakkot>
the idea is that sometimes your thing is async only because it needs to call a user-provided function, which may or may not be async
07:45
<bakkot>
if the user-provided function is async, you of course need to be async
07:45
<bakkot>
if it is not, it is nice not to be
07:46
<bakkot>
(the post has a concrete example of when that might come up)
07:48
<ljharb>
but like, if the user's providing a "read file" method, why wouldn't you just return whatever it returns?
07:48
<ljharb>
like if it returns a promise, you return one, if not, not
07:50
<bakkot>
because you need to do stuff with the thing inside the promise
07:50
<ljharb>
i guess i'm just really not getting why this is an issue outside of what seems like a very rare use case - where a user is providing a maybe-sync maybe-async method, but you need to do processing on each result, and you can't call the function for the next result until you do that processing
07:50
<ljharb>
or why you couldn't have two interfaces - a sync one and an async one - that both share an internal processing function
07:51
<bakkot>
yes, you could split up all your code so that it is in continuation-passing style, and then invoke the callbacks synchronously when the result of the user-provided function is available synchronously, but the point of async-await is that writing CPS by hand sucks
07:52
<bakkot>
I invite you to go through the exercise of refactoring the getTransitiveDependencies function so that it works that way; it is not a trivial refactor
07:54
<bakkot>
this problem comes up basically any time you're writing a utility which takes a function as an argument and does something with the return value of that function; this is not rare, in my experience, though it may be in yours
07:55
<ljharb>
certainly that's not rare in my experience, i do that all the time, but i've never had this problem come up before that i can recall
07:55
<ljharb>
but to be fair i almost never use async/await (altho i often work with promises)
07:56
<ljharb>
i also often write eslint code that works sync with dependencies - like the ExportsMap in eslint-plugin-import - but it doesn't accept a user-provided file reading mechanism, it just hardcodes it
07:58
<bakkot>
yeah, if you hardcode all your IO the issue comes up less; I generally try pretty hard to keep the IO at the boundaries, so that the core logic doesn't do any IO itself
07:58
<bakkot>
except by invoking user-provided stuff
08:00
<bakkot>
it does still come up, though; the last time I ran into this problem was when I wanted to offload some expensive computation to a worker, which meant the result of the computation was suddenly async, and I had to go rewrite everything to add async in a bunch of places and the library was no longer usable in sync contexts
08:01
<ljharb>
why do you need async everywhere versus return isPromise(p) ? p.then(f) : f(p) or something?
08:01
<bakkot>
because the function call is in the middle of a bunch of other logic
08:03
<bakkot>
for (let item of items) {
  try {
    let init = foo(item);
    // 10 more lines here
    result = await expensiveCompute(result, init);
  } catch (e) {
    // 10 more lines here
  }
}
08:03
<bakkot>
it is definitely possible to refactor this so that it just uses .then instead of await, but it's extremely annoying