question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

no-undef on AggregateError

See original GitHub issue

Tell us about your environment

I’m using github-actions to run tests on my code.

–env-info got:

Environment Info:

Node version: v14.15.4
npm version: v6.14.10
Local ESLint version: v7.19.0 (Currently used)
Global ESLint version: Not found
  • Operating System: I’m using github actions, so it tests on all 3 of the following:
          - ubuntu-latest
          - macos-latest
          - windows-latest

However ubuntu-latest failed first, so github-actions skipped the other checks.

What parser (default, @babel/eslint-parser, @typescript-eslint/parser, etc.) are you using? @babel/eslint-parser

Please show your full configuration:

Configuration

You can see the file here: https://github.com/icecream17/tic-tac-toe-grow-for-website/blob/main/.github/workflows/main.yml

      - uses: actions/setup-node@v2.1.4
        with:
          node-version: '14.15'

      - name: Install babel eslint
        run: npm install --save-dev eslint @babel/core @babel/eslint-parser @babel/eslint-plugin @babel/preset-env @babel/plugin-syntax-class-properties

What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.

https://github.com/icecream17/tic-tac-toe-grow-for-website/blob/e1040b4403f9236a3aa31e81602c0b383a392abb/game.js

// My code is 1446 lines long, so much of it isn't really important to this issue
// So here, you can see the basic structure and better understand where the error is happening.
//////////////////////////////////////

async function example() {
   // Simulates chance of error happening sometime in the future............
   // In the real code the error is inside an if statement too.
   if (Math.random()) {
      let promiseGroup = await Promise.allSettled([1, 2, 3])
      throw new AggregateError(promiseGroup);
   }
}

// Browser call
document.someElement.onclick = example();
      - name: Check game.js
        run: ./node_modules/.bin/eslint --format codeframe --color game.js

      - name: Check tournament.js
        run: ./node_modules/.bin/eslint --format codeframe --color tournament.js

Which corresponds to

./node_modules/.bin/eslint --format codeframe --color game.js

It failed at “game.js” so it didn’t get to do “tournament.js”.

What did you expect to happen? No errors when using AggregateError

What actually happened? Please copy-paste the actual, raw output from ESLint. no-undef: AggregateError is not defined

Better highlighting at: https://github.com/icecream17/tic-tac-toe-grow-for-website/runs/1888640229?check_suite_focus=true

Wow, raw output.

warning: Return values from promise executor functions cannot be read (no-promise-executor-return) at game.js:23:40:
  21 |  */
  22 | async function pause(ms) {
> 23 |    return await new Promise(resolve => setTimeout(resolve, ms, "Done!"));
     |                                        ^
  24 | }
  25 |
  26 | /**


warning: Missing semicolon (@babel/semi) at game.js:46:25:
  44 |       if (this[i] !== arr[i])
  45 |          if (!Array.isArray(this[i]) || !Array.isArray(arr[i]))
> 46 |             return false
     |                         ^
  47 |          else if (!this[i].valuesEqual(arr[i]))
  48 |             return false;
  49 |    return true;


warning: Missing semicolon (@babel/semi) at game.js:50:2:
  48 |             return false;
  49 |    return true;
> 50 | }
     |  ^
  51 |
  52 | /**
  53 |  * Represents an explicit and somewhat anticipated error


warning: This line has a length of 127. Maximum allowed is 120 (max-len) at game.js:72:1:
  70 |     * I'll just say it's not under the Apache License.
  71 |     *
> 72 |     * @param {...*} [args] - The args to the Error constructor. The only guaranteed argument is a string for the error message.
     | ^
  73 |     */
  74 |    constructor (...args) {
  75 |       super(...args);


warning: Unnecessary { after 'if' condition (curly) at game.js:79:7:
  77 |       // Maintains proper stack trace for where our error was thrown (only available on V8)
  78 |       // You must be pretty sure, and have a really good reason to pass this if statement
> 79 |       if (String(Error?.captureStackTrace).includes("native code")) {
     |       ^
  80 |          Error.captureStackTrace(this, CustomError);
  81 |       } else {
  82 |          this.stack = (new Error(...args)).stack;


warning: Unnecessary { after 'else' (curly) at game.js:81:9:
  79 |       if (String(Error?.captureStackTrace).includes("native code")) {
  80 |          Error.captureStackTrace(this, CustomError);
> 81 |       } else {
     |         ^
  82 |          this.stack = (new Error(...args)).stack;
  83 |       }
  84 |    }


warning: Operator '=' must be spaced (space-infix-ops) at game.js:98:20:
   96 |     * Derived from https://stackoverflow.com/a/42755876 by Matt
   97 |     */
>  98 |    rethrow (message=this.message, ...args) {
      |                    ^
   99 |       if (message !== this.message) {
  100 |          let newError = new (this.constructor)(message, ...args);
  101 |          newError.originalError = this;


warning: Unexpected negated condition (no-negated-condition) at game.js:99:7:
   97 |     */
   98 |    rethrow (message=this.message, ...args) {
>  99 |       if (message !== this.message) {
      |       ^
  100 |          let newError = new (this.constructor)(message, ...args);
  101 |          newError.originalError = this;
  102 |          newError.stack = `${newError.stack}\n${this.stack}`;


warning: Unnecessary parentheses around expression (no-extra-parens) at game.js:100:29:
   98 |    rethrow (message=this.message, ...args) {
   99 |       if (message !== this.message) {
> 100 |          let newError = new (this.constructor)(message, ...args);
      |                             ^
  101 |          newError.originalError = this;
  102 |          newError.stack = `${newError.stack}\n${this.stack}`;
  103 |          throw newError;


warning: Unnecessary parentheses around expression (no-extra-parens) at game.js:105:27:
  103 |          throw newError;
  104 |       } else {
> 105 |          this.stack = new (this.constructor)(message, ...args);
      |                           ^
  106 |          throw this;
  107 |       }
  108 |    }


warning: Expected an error object to be thrown (no-throw-literal) at game.js:106:10:
  104 |       } else {
  105 |          this.stack = new (this.constructor)(message, ...args);
> 106 |          throw this;
      |          ^
  107 |       }
  108 |    }
  109 | }


warning: This line has a length of 132. Maximum allowed is 120 (max-len) at game.js:124:1:
  122 |
  123 | class NothingDisabledError extends CustomError {
> 124 |    constructor (noun = "Nothing", plural = `${noun}s`, message = `Cannot enable ${noun} since all ${plural} are already enabled.`) {
      | ^
  125 |       super(message);
  126 |    }
  127 | }


warning: This line has a length of 134. Maximum allowed is 120 (max-len) at game.js:130:1:
  128 |
  129 | class NothingEnabledError extends CustomError {
> 130 |    constructor (noun = "Nothing", plural = `${noun}s`, message = `Cannot disable ${noun} since all ${plural} are already disabled.`) {
      | ^
  131 |       super(message);
  132 |    }
  133 | }


warning: 'NOT_DONE_YET' is assigned a value but never used (no-unused-vars) at game.js:220:7:
  218 |    EVIL_CHANGE: new EvilPlayerError("How did you do that"),
  219 | };
> 220 | const NOT_DONE_YET = "This feature is not finished yet. So it doesn't work";
      |       ^
  221 |
  222 | class Position {
  223 |    constructor (x, y) {


warning: Expected indentation of 6 spaces but found 9 (indent) at game.js:394:1:
  392 |       // Converted from an "if, else if, else" statement.
  393 |       switch (result[0]) {
> 394 |          case "win":
      | ^
  395 |             {
  396 |                notice("WINNNN", result);
  397 |                for (let cell of result[1].flat().concat(this.board[lastY][lastX]))


warning: Expected indentation of 9 spaces but found 12 (indent) at game.js:395:1:
  393 |       switch (result[0]) {
  394 |          case "win":
> 395 |             {
      | ^
  396 |                notice("WINNNN", result);
  397 |                for (let cell of result[1].flat().concat(this.board[lastY][lastX]))
  398 |                   cell.win = true;


warning: Expected indentation of 12 spaces but found 15 (indent) at game.js:396:1:
  394 |          case "win":
  395 |             {
> 396 |                notice("WINNNN", result);
      | ^
  397 |                for (let cell of result[1].flat().concat(this.board[lastY][lastX]))
  398 |                   cell.win = true;
  399 |


warning: Expected indentation of 12 spaces but found 15 (indent) at game.js:397:1:
  395 |             {
  396 |                notice("WINNNN", result);
> 397 |                for (let cell of result[1].flat().concat(this.board[lastY][lastX]))
      | ^
  398 |                   cell.win = true;
  399 |
  400 |                let winArray = [this.toMove, PLAYER_NAMES[this.toMove], players[this.toMove].player];


warning: Expected indentation of 15 spaces but found 18 (indent) at game.js:398:1:
  396 |                notice("WINNNN", result);
  397 |                for (let cell of result[1].flat().concat(this.board[lastY][lastX]))
> 398 |                   cell.win = true;
      | ^
  399 |
  400 |                let winArray = [this.toMove, PLAYER_NAMES[this.toMove], players[this.toMove].player];
  401 |                if (this.winners.every(array => !array.valuesEqual(winArray)))


warning: Expected indentation of 12 spaces but found 15 (indent) at game.js:400:1:
  398 |                   cell.win = true;
  399 |
> 400 |                let winArray = [this.toMove, PLAYER_NAMES[this.toMove], players[this.toMove].player];
      | ^
  401 |                if (this.winners.every(array => !array.valuesEqual(winArray)))
  402 |                   this.winners.push(winArray);
  403 |             }


warning: Expected indentation of 12 spaces but found 15 (indent) at game.js:401:1:
  399 |
  400 |                let winArray = [this.toMove, PLAYER_NAMES[this.toMove], players[this.toMove].player];
> 401 |                if (this.winners.every(array => !array.valuesEqual(winArray)))
      | ^
  402 |                   this.winners.push(winArray);
  403 |             }
  404 |             break;


warning: Expected indentation of 15 spaces but found 18 (indent) at game.js:402:1:
  400 |                let winArray = [this.toMove, PLAYER_NAMES[this.toMove], players[this.toMove].player];
  401 |                if (this.winners.every(array => !array.valuesEqual(winArray)))
> 402 |                   this.winners.push(winArray);
      | ^
  403 |             }
  404 |             break;
  405 |          case "draw":


warning: Expected indentation of 9 spaces but found 12 (indent) at game.js:403:1:
  401 |                if (this.winners.every(array => !array.valuesEqual(winArray)))
  402 |                   this.winners.push(winArray);
> 403 |             }
      | ^
  404 |             break;
  405 |          case "draw":
  406 |             notice(`*gasp*! Draw!\n${result[1]}`, result);


warning: Expected indentation of 9 spaces but found 12 (indent) at game.js:404:1:
  402 |                   this.winners.push(winArray);
  403 |             }
> 404 |             break;
      | ^
  405 |          case "draw":
  406 |             notice(`*gasp*! Draw!\n${result[1]}`, result);
  407 |             break;


warning: Expected indentation of 6 spaces but found 9 (indent) at game.js:405:1:
  403 |             }
  404 |             break;
> 405 |          case "draw":
      | ^
  406 |             notice(`*gasp*! Draw!\n${result[1]}`, result);
  407 |             break;
  408 |          default:


warning: Expected indentation of 9 spaces but found 12 (indent) at game.js:406:1:
  404 |             break;
  405 |          case "draw":
> 406 |             notice(`*gasp*! Draw!\n${result[1]}`, result);
      | ^
  407 |             break;
  408 |          default:
  409 |             ERRORS.INVALID_MOVE_FINISH.rethrow();


warning: Expected indentation of 9 spaces but found 12 (indent) at game.js:407:1:
  405 |          case "draw":
  406 |             notice(`*gasp*! Draw!\n${result[1]}`, result);
> 407 |             break;
      | ^
  408 |          default:
  409 |             ERRORS.INVALID_MOVE_FINISH.rethrow();
  410 |       }


warning: Expected indentation of 6 spaces but found 9 (indent) at game.js:408:1:
  406 |             notice(`*gasp*! Draw!\n${result[1]}`, result);
  407 |             break;
> 408 |          default:
      | ^
  409 |             ERRORS.INVALID_MOVE_FINISH.rethrow();
  410 |       }
  411 |    }


warning: Expected indentation of 9 spaces but found 12 (indent) at game.js:409:1:
  407 |             break;
  408 |          default:
> 409 |             ERRORS.INVALID_MOVE_FINISH.rethrow();
      | ^
  410 |       }
  411 |    }
  412 |


warning: Missing semicolon (@babel/semi) at game.js:454:8:
  452 |
  453 |          return diag;
> 454 |       }
      |        ^
  455 |
  456 |       for (let i = 0; i < 4; i++) {
  457 |          const orthogonalStep = [


warning: Missing semicolon (@babel/semi) at game.js:554:8:
  552 |
  553 |          return newWins;
> 554 |       }
      |        ^
  555 |
  556 |       wins.push(...checkmarks(diagonal[0], diagonal[3], new Step(1, -1), new Step(-1, 1)));
  557 |       wins.push(...checkmarks(diagonal[1], diagonal[2], new Step(1, 1), new Step(-1, -1)));


warning: Missing semicolon (@babel/semi) at game.js:600:26:
  598 |          for (let x = 0; x < this.board.width; x++) {
  599 |             let char = this.board[y][x].value;
> 600 |             ascii += '%c'
      |                          ^
  601 |             if (char === '') {
  602 |                ascii += ' ';
  603 |                css.push('background-color:gray');


warning: Unexpected string concatenation (prefer-template) at game.js:610:19:
  608 |                ascii += char;
  609 |                css.push(
> 610 |                   "color:"
      |                   ^
  611 |                   + ['red', 'blue', 'green', 'orange', 'purple'][PLAYER_CHARS.indexOf(char)]
  612 |                   + (this.board[y][x].win ? ';background-color:#CFC' : '')
  613 |                );


warning: Missing semicolon (@babel/semi) at game.js:625:8:
  623 |          'background-color:gray;color:gray',
  624 |          'color:white'
> 625 |       )
      |        ^
  626 |
  627 |       if (verbose) console.debug(ascii, ...css);
  628 |       else console.log(ascii, ...css);


warning: '=' should be placed at the beginning of the line (operator-linebreak) at game.js:750:41:
  748 |
  749 |    updateVisualStats() {
> 750 |       ELEMENTS.statsParagraph.innerText =
      |                                         ^
  751 | `Width: ${this.board.width}
  752 | Height: ${this.board.height}
  753 | Turns: ${this.turn}`;


warning: 'args' is defined but never used (no-unused-vars) at game.js:823:20:
  821 | }
  822 |
> 823 | function notice(...args) {
      |                    ^
  824 |    // TODO: do something
  825 | }
  826 |


warning: Missing semicolon (@babel/semi) at game.js:921:2:
  919 |    currentGame.updateVisual();
  920 |    currentGame.updateVisualStats();
> 921 | }
      |  ^
  922 |
  923 | // Assumes that the enable and disable buttons are disabled / enabled when appropriate.
  924 | // For example, the enable button should not be enabled if the element is already enabled.


warning: Unnecessary parentheses around expression (no-extra-parens) at game.js:1053:32:
  1051 |          bot_mechanics.random_move.apply(this);
  1052 |       else {
> 1053 |          let indexOfLastMove = (
       |                                ^
  1054 |             lastMove.gameState
  1055 |                .originalMoves
  1056 |                .findIndex(


warning: Missing semicolon (@babel/semi) at game.js:1071:39:
  1069 |    avoider() {
  1070 |       let moves = this.getMoves();
> 1071 |       let best_moves = [-Infinity, []]
       |                                       ^
  1072 |       for (let move of moves) {
  1073 |          let score = 0;
  1074 |          for (let historicalMove of this.moveHistory)


warning: Unnecessary parentheses around expression (no-extra-parens) at game.js:1110:50:
  1108 |       } else positionOnDiagonal = new Position(0, 0);
  1109 |
> 1110 |       let moves = this.getMoves().filter(move => (
       |                                                  ^
  1111 |          (positionOnDiagonal.x + positionOnDiagonal.y + move.x + move.y) % 2 === 0
  1112 |       ));
  1113 |       if (moves.length === 0)


warning: A function with a name starting with an uppercase letter should only be used as a constructor (@babel/new-cap) at game.js:1220:33:
  1218 |
  1219 |    let localIndex = Array.prototype.indexOf.call(option.parentElement.children, option);
> 1220 |    if (localIndex === -1) throw ReferenceError("No player is selected!??");
       |                                 ^
  1221 |
  1222 |    players[playerIndex] = new PlayerReference(type, localIndex);
  1223 |    currentGame.playBots();


warning: Operator '=' must be spaced (space-infix-ops) at game.js:1239:45:
  1237 |
  1238 | // this = <input>
> 1239 | async function enablePerson(fromEnablePeople=false) {
       |                                             ^
  1240 |    // MAX_PLAYERS_REACHED and EVERYONEs_ENABLED both fit...
  1241 |    if (activePeople === 4) ERRORS.EVERYONEs_ENABLED.rethrow();
  1242 |    activePeople++;


warning: Operator '=' must be spaced (space-infix-ops) at game.js:1260:47:
  1258 |
  1259 | // Bug, probably feature: Player not changed when disabled
> 1260 | async function disablePerson(fromDisablePeople=false) {
       |                                               ^
  1261 |    if (activePeople === 0) ERRORS.NO_ONEs_ENABLED.rethrow();
  1262 |    activePeople--;
  1263 |


error: 'AggregateError' is not defined (no-undef) at game.js:1294:52:
  1292 |    let promiseGroup = await Promise.allSettled(clickPromises);
  1293 |    for (let promise of promiseGroup)
> 1294 |       if (promise.status === 'rejected') throw new AggregateError(promiseGroup);
       |                                                    ^
  1295 |
  1296 |    if (counter !== num)
  1297 |       console.warn(`Failed to enable the correct amount: ${counter} !== ${num}`);


error: 'AggregateError' is not defined (no-undef) at game.js:1317:52:
  1315 |    let promiseGroup = await Promise.allSettled(clickPromises);
  1316 |    for (let promise of promiseGroup)
> 1317 |       if (promise.status === 'rejected') throw new AggregateError(promiseGroup);
       |                                                    ^
  1318 |
  1319 |    activePeople = counter;
  1320 |    if (counter !== num)


warning: Possible race condition: `activePeople` might be reassigned based on an outdated value of `activePeople` (require-atomic-updates) at game.js:1319:4:
  1317 |       if (promise.status === 'rejected') throw new AggregateError(promiseGroup);
  1318 |
> 1319 |    activePeople = counter;
       |    ^
  1320 |    if (counter !== num)
  1321 |       console.warn(`Failed to disable the correct amount: ${counter} !== ${num}`);
  1322 |


warning: Operator '=' must be spaced (space-infix-ops) at game.js:1327:46:
  1325 |
  1326 | // this = <select disabled>
> 1327 | async function enablePlayer(fromEnablePlayers=false) {
       |                                              ^
  1328 |    if (activePlayers === 4) ERRORS.MAX_PLAYERS_REACHED.rethrow();
  1329 |
  1330 |    let playerIndex = this.parentElement.id[8] - 1;


warning: 'fromDisablePlayers' is assigned a value but never used (no-unused-vars) at game.js:1358:30:
  1356 | // Min players: !1 (apparently it's 0)
  1357 | // this = <input (not:disabled)>
> 1358 | async function disablePlayer(fromDisablePlayers=false) {
       |                              ^
  1359 |    if (activePlayers === 0) ERRORS.NO_ONEs_ENABLED.rethrow();
  1360 |
  1361 |    let option = this.selectedOptions[0];


warning: Operator '=' must be spaced (space-infix-ops) at game.js:1358:48:
  1356 | // Min players: !1 (apparently it's 0)
  1357 | // this = <input (not:disabled)>
> 1358 | async function disablePlayer(fromDisablePlayers=false) {
       |                                                ^
  1359 |    if (activePlayers === 0) ERRORS.NO_ONEs_ENABLED.rethrow();
  1360 |
  1361 |    let option = this.selectedOptions[0];


warning: Missing semicolon (@babel/semi) at game.js:1373:88:
  1371 |       ELEMENTS.playerSelects[playerIndexPlusOne].dispatchEvent(new Event("change"));
  1372 |
> 1373 |       return await disablePlayer.call(ELEMENTS.playerSelects[playerIndexPlusOne], true)
       |                                                                                        ^
  1374 |    } else {
  1375 |       this.disabled = true;
  1376 |       this.parentElement.nextElementSibling.disabled = false;


warning: 'activeBots' is assigned a value but never used (no-unused-vars) at game.js:1383:50:
  1381 |
  1382 |       // <optgroup> label
> 1383 |       if (option.parentElement.label === "Bots") activeBots--;
       |                                                  ^
  1384 |       else activePeople--;
  1385 |
  1386 |       if (currentGame.toMove === playerIndexPlusOne - 1) {


error: 'AggregateError' is not defined (no-undef) at game.js:1411:52:
  1409 |    let promiseGroup = await Promise.allSettled(clickPromises);
  1410 |    for (let promise of promiseGroup)
> 1411 |       if (promise.status === 'rejected') throw new AggregateError(promiseGroup);
       |                                                    ^
  1412 |
  1413 |    if (counter !== num)
  1414 |       console.warn(`Failed to enable the correct amount: ${counter} !== ${num}`);


error: 'AggregateError' is not defined (no-undef) at game.js:1433:52:
  1431 |    let promiseGroup = await Promise.allSettled(clickPromises);
  1432 |    for (let promise of promiseGroup)
> 1433 |       if (promise.status === 'rejected') throw new AggregateError(promiseGroup);
       |                                                    ^
  1434 |
  1435 |    if (counter !== num)
  1436 |       console.warn(`Failed to disable the correct amount: ${counter} !== ${num}`);


4 errors and 49 warnings found.
37 warnings potentially fixable with the `--fix` option.
Error: Process completed with exit code 1.

Steps to reproduce this issue:

  1. Use AggregateError in your code
  2. Watch as your tests fail because AggregateError is not defined

Are you willing to submit a pull request to fix this bug? No

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
mdjermanoviccommented, Feb 12, 2021

Hi @icecream17, thanks for the issue!

I can see you fixed the issue for now by adding "AggregateError" to globals 👍

It seems that we missed adding this to built-in environments. By the finished proposals list, it looks like this should be in the es2021 environment (the expected publication year for https://github.com/tc39/proposal-promise-any is 2021).

1reaction
mdjermanoviccommented, Feb 12, 2021

When making this change, it’d be great to also ensure WeakRef and FinalizationRegistry are in the es2021 list.

Those two should be already there.

Read more comments on GitHub >

github_iconTop Results From Across the Web

AggregateError - David Walsh Blog
The AggregateError error lets developers throw multiple errors within one single Error . Let's see how it works.
Read more >
21.03 - Teradici
... MIT License agent-base 6.0.2 : MIT License aggregate-error 3.1.0 : MIT License aheckmann/mquery 3.2.3 : MIT License ajv 6.12.0 : MIT License...
Read more >
mozilla-inbound: pushlog
... Bug 1568903 - Part 4: Implement AggregateError for Nightly. r=jorendorff ... dom/media/test/ - Enable ESLint rules no-undef and no-unused-vars. r=jya.
Read more >
Open Source Used In Intersight Mobile App 1.0.275 - Cisco
This document contains licenses and notices for open source software used in this product.
Read more >
D81678 Introduce noundef attribute at call sites for ... - LLVM
This change adds a new IR noundef attribute, which denotes when a function call argument or return val may never contain uninitialized bits....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found