Enable the prefer-destructuring eslint rule (#1858)

## Description:

Enable the `prefer-destructuring` eslint rule.

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
This commit is contained in:
Scott Anderson
2025-08-18 20:45:21 -04:00
committed by GitHub
parent 42394d4476
commit 7bb319fcad
29 changed files with 43 additions and 40 deletions
+4
View File
@@ -118,6 +118,10 @@ export default [
"object-shorthand": ["error", "always"], "object-shorthand": ["error", "always"],
"no-undef": "error", "no-undef": "error",
"no-unused-vars": "off", // @typescript-eslint/no-unused-vars "no-unused-vars": "off", // @typescript-eslint/no-unused-vars
"prefer-destructuring": ["error", {
array: false,
object: true,
}],
"quote-props": ["error", "consistent-as-needed"], "quote-props": ["error", "consistent-as-needed"],
"sort-imports": "error", "sort-imports": "error",
"space-before-blocks": ["error", "always"], "space-before-blocks": ["error", "always"],
+1 -1
View File
@@ -288,7 +288,7 @@ export class ClientGameRunner {
this.saveGame(gu.updates[GameUpdateType.Win][0]); this.saveGame(gu.updates[GameUpdateType.Win][0]);
} }
}); });
const worker = this.worker; const { worker } = this;
const keepWorkerAlive = () => { const keepWorkerAlive = () => {
if (this.isActive) { if (this.isActive) {
worker.sendHeartbeat(); worker.sendHeartbeat();
+1 -1
View File
@@ -613,7 +613,7 @@ function hasAllowedFlare(
const allowed = config.allowedFlares(); const allowed = config.allowedFlares();
if (allowed === undefined) return true; if (allowed === undefined) return true;
if (userMeResponse === false) return false; if (userMeResponse === false) return false;
const flares = userMeResponse.player.flares; const { flares } = userMeResponse.player;
if (flares === undefined) return false; if (flares === undefined) return false;
return allowed.length === 0 || allowed.some((f) => flares.includes(f)); return allowed.length === 0 || allowed.some((f) => flares.includes(f));
} }
+1 -1
View File
@@ -389,7 +389,7 @@ export function generatePreviewDataUrl(
// Create an image // Create an image
const imageData = ctx.createImageData(width, height); const imageData = ctx.createImageData(width, height);
const data = imageData.data; const { data } = imageData;
let i = 0; let i = 0;
for (let y = 0; y < height; y++) { for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) { for (let x = 0; x < width; x++) {
+1 -1
View File
@@ -115,7 +115,7 @@ export const translateText = (
let message = langSelector.translations[key]; let message = langSelector.translations[key];
if (!message && langSelector.defaultTranslations) { if (!message && langSelector.defaultTranslations) {
const defaultTranslations = langSelector.defaultTranslations; const { defaultTranslations } = langSelector;
if (defaultTranslations && defaultTranslations[key]) { if (defaultTranslations && defaultTranslations[key]) {
message = defaultTranslations[key]; message = defaultTranslations[key];
} }
@@ -74,7 +74,7 @@ export class SettingKeybind extends LitElement {
if (!this.listening) return; if (!this.listening) return;
e.preventDefault(); e.preventDefault();
const code = e.code; const { code } = e;
this.value = code; this.value = code;
+2 -2
View File
@@ -85,8 +85,8 @@ export function createGrid(
.fill(null as unknown as boolean[]) .fill(null as unknown as boolean[])
.map(() => Array<boolean>(height).fill(false)); .map(() => Array<boolean>(height).fill(false));
for (let x = scaledBoundingBox.min.x; x <= scaledBoundingBox.max.x; x++) { for (let { x } = scaledBoundingBox.min; x <= scaledBoundingBox.max.x; x++) {
for (let y = scaledBoundingBox.min.y; y <= scaledBoundingBox.max.y; y++) { for (let { y } = scaledBoundingBox.min; y <= scaledBoundingBox.max.y; y++) {
const cell = new Cell(x * scalingFactor, y * scalingFactor); const cell = new Cell(x * scalingFactor, y * scalingFactor);
if (game.isOnMap(cell)) { if (game.isOnMap(cell)) {
const tile = game.ref(cell.x, cell.y); const tile = game.ref(cell.x, cell.y);
+1 -1
View File
@@ -124,7 +124,7 @@ export const colorizeCanvas = (
ctx.drawImage(source, 0, 0); ctx.drawImage(source, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; const { data } = imageData;
const colorARgb = colorA.toRgb(); const colorARgb = colorA.toRgb();
const colorBRgb = colorB.toRgb(); const colorBRgb = colorB.toRgb();
+2 -2
View File
@@ -18,8 +18,8 @@ export function conquestFxFactory(
): Fx[] { ): Fx[] {
const conquestFx: Fx[] = []; const conquestFx: Fx[] = [];
const conquered = game.player(conquest.conqueredId); const conquered = game.player(conquest.conqueredId);
const x = conquered.nameLocation().x; const { x } = conquered.nameLocation();
const y = conquered.nameLocation().y; const { y } = conquered.nameLocation();
const swordAnimation = new SpriteFx( const swordAnimation = new SpriteFx(
animatedSpriteLoader, animatedSpriteLoader,
+4 -4
View File
@@ -71,11 +71,11 @@ export class FxLayer implements Layer {
// Only display text fx for the current player // Only display text fx for the current player
return; return;
} }
const tile = bonus.tile; const { tile } = bonus;
const x = this.game.x(tile); const x = this.game.x(tile);
let y = this.game.y(tile); let y = this.game.y(tile);
const gold = bonus.gold; const { gold } = bonus;
const troops = bonus.troops; const { troops } = bonus;
if (gold > 0) { if (gold > 0) {
const shortened = renderNumber(gold, 0); const shortened = renderNumber(gold, 0);
@@ -149,7 +149,7 @@ export class FxLayer implements Layer {
} }
onRailroadEvent(railroad: RailroadUpdate) { onRailroadEvent(railroad: RailroadUpdate) {
const railTiles = railroad.railTiles; const { railTiles } = railroad;
for (const rail of railTiles) { for (const rail of railTiles) {
// No need for pseudorandom, this is fx // No need for pseudorandom, this is fx
const chanceFx = Math.floor(Math.random() * 3); const chanceFx = Math.floor(Math.random() * 3);
+1 -1
View File
@@ -233,7 +233,7 @@ export class NameLayer implements Layer {
}; };
if (player.cosmetics.flag) { if (player.cosmetics.flag) {
const flag = player.cosmetics.flag; const { flag } = player.cosmetics;
if (flag !== undefined && flag !== null && flag.startsWith("!")) { if (flag !== undefined && flag !== null && flag.startsWith("!")) {
const flagWrapper = document.createElement("div"); const flagWrapper = document.createElement("div");
applyFlagStyles(flagWrapper); applyFlagStyles(flagWrapper);
@@ -532,7 +532,7 @@ export class StructureIconsLayer implements Layer {
const screenPos = this.transformHandler.worldToScreenCoordinates(worldPos); const screenPos = this.transformHandler.worldToScreenCoordinates(worldPos);
const { type, stage } = options; const { type, stage } = options;
const scale = this.transformHandler.scale; const { scale } = this.transformHandler;
const spritesEnabled = this.game const spritesEnabled = this.game
.config() .config()
.userSettings() .userSettings()
@@ -612,7 +612,7 @@ export class StructureIconsLayer implements Layer {
const screenPos = this.transformHandler.worldToScreenCoordinates(worldPos); const screenPos = this.transformHandler.worldToScreenCoordinates(worldPos);
screenPos.x = Math.round(screenPos.x); screenPos.x = Math.round(screenPos.x);
const scale = this.transformHandler.scale; const { scale } = this.transformHandler;
screenPos.y = Math.round( screenPos.y = Math.round(
scale >= ZOOM_THRESHOLD && scale >= ZOOM_THRESHOLD &&
this.game.config().userSettings()?.structureSprites() this.game.config().userSettings()?.structureSprites()
+2 -2
View File
@@ -393,7 +393,7 @@ export class TerritoryLayer implements Layer {
break; break;
} }
const tile = entry.tile; const { tile } = entry;
this.paintTerritory(tile); this.paintTerritory(tile);
for (const neighbor of this.game.neighbors(tile)) { for (const neighbor of this.game.neighbors(tile)) {
this.paintTerritory(neighbor, true); this.paintTerritory(neighbor, true);
@@ -455,7 +455,7 @@ export class TerritoryLayer implements Layer {
} }
} else { } else {
// Interior tiles // Interior tiles
const pattern = owner.cosmetics.pattern; const { pattern } = owner.cosmetics;
const patternsEnabled = this.cachedTerritoryPatternsEnabled ?? false; const patternsEnabled = this.cachedTerritoryPatternsEnabled ?? false;
// Alternative view only shows borders. // Alternative view only shows borders.
+1 -1
View File
@@ -263,7 +263,7 @@ export class UILayer implements Layer {
* Draw health bar for a unit * Draw health bar for a unit
*/ */
public drawHealthBar(unit: UnitView) { public drawHealthBar(unit: UnitView) {
const maxHealth = this.game.unitInfo(unit.type()).maxHealth; const { maxHealth } = this.game.unitInfo(unit.type());
if (maxHealth === undefined || this.context === null) { if (maxHealth === undefined || this.context === null) {
return; return;
} }
@@ -36,7 +36,7 @@ export function renderUnitTypeOptions({
type="checkbox" type="checkbox"
.checked=${disabledUnits.includes(type)} .checked=${disabledUnits.includes(type)}
@change=${(e: Event) => { @change=${(e: Event) => {
const checked = (e.target as HTMLInputElement).checked; const { checked } = (e.target as HTMLInputElement);
toggleUnit(type, checked); toggleUnit(type, checked);
}} }}
/> />
+1 -1
View File
@@ -41,7 +41,7 @@ export class PseudoRandom {
// Selects a random element from a set. // Selects a random element from a set.
randFromSet<T>(set: Set<T>): T { randFromSet<T>(set: Set<T>): T {
const size = set.size; const { size } = set;
if (size === 0) { if (size === 0) {
throw new Error("set must not be empty"); throw new Error("set must not be empty");
} }
+1 -1
View File
@@ -99,7 +99,7 @@ export class ConstructionExecution implements Execution {
} }
private completeConstruction() { private completeConstruction() {
const player = this.player; const { player } = this;
switch (this.constructionType) { switch (this.constructionType) {
case UnitType.AtomBomb: case UnitType.AtomBomb:
case UnitType.HydrogenBomb: case UnitType.HydrogenBomb:
+4 -4
View File
@@ -67,7 +67,7 @@ export class FakeHumanExecution implements Execution {
} }
private updateRelationsFromEmbargos() { private updateRelationsFromEmbargos() {
const player = this.player; const { player } = this;
if (player === null) return; if (player === null) return;
const others = this.mg.players().filter((p) => p.id() !== player.id()); const others = this.mg.players().filter((p) => p.id() !== player.id());
@@ -90,7 +90,7 @@ export class FakeHumanExecution implements Execution {
} }
private handleEmbargoesToHostileNations() { private handleEmbargoesToHostileNations() {
const player = this.player; const { player } = this;
if (player === null) return; if (player === null) return;
const others = this.mg.players().filter((p) => p.id() !== player.id()); const others = this.mg.players().filter((p) => p.id() !== player.id());
@@ -248,7 +248,7 @@ export class FakeHumanExecution implements Execution {
if (other.isTraitor()) { if (other.isTraitor()) {
return false; return false;
} }
const difficulty = this.mg.config().gameConfig().difficulty; const { difficulty } = this.mg.config().gameConfig();
if ( if (
difficulty === Difficulty.Hard || difficulty === Difficulty.Hard ||
difficulty === Difficulty.Impossible difficulty === Difficulty.Impossible
@@ -491,7 +491,7 @@ export class FakeHumanExecution implements Execution {
private structureSpawnTileValue(type: UnitType): (tile: TileRef) => number { private structureSpawnTileValue(type: UnitType): (tile: TileRef) => number {
if (this.player === null) throw new Error("not initialized"); if (this.player === null) throw new Error("not initialized");
const borderTiles = this.player.borderTiles(); const borderTiles = this.player.borderTiles();
const mg = this.mg; const { mg } = this;
const otherUnits = this.player.units(type); const otherUnits = this.player.units(type);
// Prefer spacing structures out of atom bomb range // Prefer spacing structures out of atom bomb range
const borderSpacing = this.mg.config().nukeMagnitudes(UnitType.AtomBomb).outer; const borderSpacing = this.mg.config().nukeMagnitudes(UnitType.AtomBomb).outer;
+1 -1
View File
@@ -27,7 +27,7 @@ export class PortExecution implements Execution {
throw new Error("Not initialized"); throw new Error("Not initialized");
} }
if (this.port === null) { if (this.port === null) {
const tile = this.tile; const { tile } = this;
const spawn = this.player.canBuild(UnitType.Port, tile); const spawn = this.player.canBuild(UnitType.Port, tile);
if (spawn === false) { if (spawn === false) {
console.warn( console.warn(
+1 -1
View File
@@ -21,7 +21,7 @@ export class RailroadExecution implements Execution {
/* eslint-disable sort-keys */ /* eslint-disable sort-keys */
init(mg: Game, ticks: number): void { init(mg: Game, ticks: number): void {
this.mg = mg; this.mg = mg;
const tiles = this.railRoad.tiles; const { tiles } = this.railRoad;
// Inverse direction computation for the first tile // Inverse direction computation for the first tile
this.railTiles.push({ this.railTiles.push({
tile: tiles[0], tile: tiles[0],
+1 -1
View File
@@ -846,7 +846,7 @@ export class PlayerImpl implements Player {
if (existing.length === 0) { if (existing.length === 0) {
return false; return false;
} }
const unit = existing[0].unit; const { unit } = existing[0];
if (!this.canUpgradeUnit(unit.type())) { if (!this.canUpgradeUnit(unit.type())) {
return false; return false;
} }
+1 -1
View File
@@ -94,7 +94,7 @@ export class UnitGrid {
private getCellsInRange(tile: TileRef, range: number) { private getCellsInRange(tile: TileRef, range: number) {
const x = this.gm.x(tile); const x = this.gm.x(tile);
const y = this.gm.y(tile); const y = this.gm.y(tile);
const cellSize = this.cellSize; const { cellSize } = this;
const [gridX, gridY] = this.getGridCoords(x, y); const [gridX, gridY] = this.getGridCoords(x, y);
const startGridX = Math.max( const startGridX = Math.max(
0, 0,
+1 -1
View File
@@ -75,7 +75,7 @@ export class SerialAStar<NodeType> implements AStar<NodeType> {
if (this.completed) return PathFindResultType.Completed; if (this.completed) return PathFindResultType.Completed;
this.maxTries -= 1; this.maxTries -= 1;
let iterations = this.iterations; let { iterations } = this;
while (!this.fwdOpenSet.isEmpty() && !this.bwdOpenSet.isEmpty()) { while (!this.fwdOpenSet.isEmpty() && !this.bwdOpenSet.isEmpty()) {
iterations--; iterations--;
+2 -2
View File
@@ -27,8 +27,8 @@ export class BezenhamLine {
if (this.p1.x === this.p2.x && this.p1.y === this.p2.y) { if (this.p1.x === this.p2.x && this.p1.y === this.p2.y) {
return true; return true;
} }
const x = this.p1.x; const { x } = this.p1;
const y = this.p1.y; const { y } = this.p1;
const err2 = 2 * this.error; const err2 = 2 * this.error;
if (err2 > -this.dy) { if (err2 > -this.dy) {
+1 -1
View File
@@ -90,7 +90,7 @@ export async function startMaster() {
cluster.on("message", (worker, message) => { cluster.on("message", (worker, message) => {
if (message.type === "WORKER_READY") { if (message.type === "WORKER_READY") {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const workerId = message.workerId; const { workerId } = message;
readyWorkers.add(workerId); readyWorkers.add(workerId);
log.info( log.info(
`Worker ${workerId} is ready. (${readyWorkers.size}/${config.numWorkers()} ready)`, `Worker ${workerId} is ready. (${readyWorkers.size}/${config.numWorkers()} ready)`,
+1 -1
View File
@@ -89,7 +89,7 @@ export async function startWorker() {
app.post( app.post(
"/api/create_game/:id", "/api/create_game/:id",
gatekeeper.httpHandler(LimiterType.Post, async (req, res) => { gatekeeper.httpHandler(LimiterType.Post, async (req, res) => {
const id = req.params.id; const { id } = req.params;
const creatorClientID = (() => { const creatorClientID = (() => {
if (typeof req.query.creatorClientID !== "string") return undefined; if (typeof req.query.creatorClientID !== "string") return undefined;
@@ -169,8 +169,7 @@ async function handleJoinMessage(
success: false, success: false,
}; };
} }
roles = result.player.roles; ({ roles, flares } = result.player);
flares = result.player.flares;
if (allowedFlares !== undefined) { if (allowedFlares !== undefined) {
// Login is required // Login is required
+1 -1
View File
@@ -79,7 +79,7 @@ describe("InputHandler AutoUpgrade", () => {
}), }),
); );
const calls = mockEmit.mock.calls; const { calls } = mockEmit.mock;
const lastCall = calls[calls.length - 1]; const lastCall = calls[calls.length - 1];
expect(lastCall[0]).not.toBeInstanceOf(AutoUpgradeEvent); expect(lastCall[0]).not.toBeInstanceOf(AutoUpgradeEvent);
}); });
+1 -1
View File
@@ -38,7 +38,7 @@ describe("Warship", () => {
}); });
test("Warship heals only if player has port", async () => { test("Warship heals only if player has port", async () => {
const maxHealth = game.config().unitInfo(UnitType.Warship).maxHealth; const { maxHealth } = game.config().unitInfo(UnitType.Warship);
if (typeof maxHealth !== "number") { if (typeof maxHealth !== "number") {
expect(typeof maxHealth).toBe("number"); expect(typeof maxHealth).toBe("number");
throw new Error("unreachable"); throw new Error("unreachable");