mooz / js2-mode

Improved JavaScript editing mode for GNU Emacs
GNU General Public License v3.0
1.33k stars 186 forks source link

js2-mode does not recognize asynchronous generators within class or object #598

Closed belden closed 11 months ago

belden commented 11 months ago

js2-mode struggles with this code. async *... within class context seems not to be recognized. The parsed function ends up not being set as async, which means the await is incorrectly flagged as occurring within a non-async function ("msg.bad.await").

#!/usr/bin/env node

class Toy {
  // (1) `async` not detected correctly
  // (2) `*` not treated correctly
  // (3) `await` treated as "msg.bad.await"

  async *oneByOne() {
    const resp = await this.getRecords();
    for (const rec of resp.records) {
      yield rec;
    }
  }

  // `async` / `await` have no parsing errors here
  async getRecords() {
    const out = await Promise.resolve({ records: [1, 2, 3] });
    return out;
  }

  // `*` treated correctly here
  *correctGeneratorDetection() {
    for (const r of [1, 2, 3]) {
      yield r;
    }
  }
}

(async () => {
  const toy = new Toy();
  for await (const rec of toy.oneByOne()) {
    console.log(rec);
  }
})();

There's also a superflous complaint from the code above that the * at *all requires a colon ("msg.no.colon.prop").

📸 click here to see screenshot ![image](https://github.com/mooz/js2-mode/assets/361683/27d66887-d14f-42fa-acf1-43d2f8e80079)

Similar, but not identical, parsing errors occur when converting the above code to a simple object. In this next example, the * in *all still shows an error ("msg.no.colon.prop"). The function is not recognized as a generator though, since yield also shows an error ("msg.bad.yield").

#!/usr/bin/env node

const obj = {
  // (1) `async` not detected correctly
  // (2) `*` not treated correctly (error: "msg.no.colon.prop")
  // (3) `yield` treated as an error (error: "msg.bad.yield")

  async *all() {
    const resp = await getRecords();
    for (const rec of resp.records) {
      yield rec;
    }
  }
};

// (4) generic "syntax error" (error: "msg.syntax")

async function getRecords() {
  return Promise.resolve({ records: [1, 2, 3] });
}

(async () => {
  for await (const rec of obj.all()) {
    console.log(rec);
  }
})();
📸 click here to see screenshot ![image](https://github.com/mooz/js2-mode/assets/361683/44fecd46-28ca-4146-baca-d07cf7261ecd)

In both cases, both pieces of code really do run, and simply log 1\n2\n3\n.


My environment:

dgutov commented 11 months ago

Hi!

Thanks for the excellent report, both cases should work now.

belden commented 11 months ago

@dgutov Thanks for the fast fix! Indeed, both toy scripts render correctly now.

dgutov commented 11 months ago

Thanks for checking. I've tagged a new release too, so that the fix is out to stable channels.