Enable eslint rule @stylistic/ts/indent (#1779)

## Description:

Enable eslint rule `@stylistic/ts/indent`. Fixes #1778

## 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-11 22:26:48 -04:00
committed by GitHub
parent ce49599229
commit a9e5aa0187
19 changed files with 257 additions and 200 deletions
+1
View File
@@ -0,0 +1 @@
*.[tj]s
+6
View File
@@ -1,5 +1,6 @@
import { includeIgnoreFile } from "@eslint/compat";
import pluginJs from "@eslint/js";
import stylisticTs from "@stylistic/eslint-plugin";
import eslintConfigPrettier from "eslint-config-prettier/flat";
import globals from "globals";
import path from "node:path";
@@ -46,8 +47,12 @@ export default [
},
},
{
plugins: {
"@stylistic/ts": stylisticTs,
},
rules: {
// Enable rules
"@stylistic/ts/indent": ["error", 2],
"@typescript-eslint/consistent-type-definitions": [
"error",
"type",
@@ -64,6 +69,7 @@ export default [
"@typescript-eslint/prefer-literal-enum-member": "error",
"@typescript-eslint/prefer-nullish-coalescing": "error",
eqeqeq: "error",
indent: "off", // @stylistic/ts/indent
"sort-keys": "error",
},
},
+49
View File
@@ -42,6 +42,7 @@
"@datastructures-js/priority-queue": "^6.3.3",
"@eslint/compat": "^1.2.7",
"@eslint/js": "^9.21.0",
"@stylistic/eslint-plugin": "^5.2.3",
"@swc/jest": "^0.2.39",
"@total-typescript/ts-reset": "^0.6.1",
"@types/benchmark": "^2.1.5",
@@ -6359,6 +6360,54 @@
"node": ">=18.0.0"
}
},
"node_modules/@stylistic/eslint-plugin": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.2.3.tgz",
"integrity": "sha512-oY7GVkJGVMI5benlBDCaRrSC1qPasafyv5dOBLLv5MTilMGnErKhO6ziEfodDDIZbo5QxPUNW360VudJOFODMw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/types": "^8.38.0",
"eslint-visitor-keys": "^4.2.1",
"espree": "^10.4.0",
"estraverse": "^5.3.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
"eslint": ">=9.0.0"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/types": {
"version": "8.39.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz",
"integrity": "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@swc/core": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.3.tgz",
+2 -1
View File
@@ -29,9 +29,10 @@
"@datastructures-js/priority-queue": "^6.3.3",
"@eslint/compat": "^1.2.7",
"@eslint/js": "^9.21.0",
"@stylistic/eslint-plugin": "^5.2.3",
"@swc/jest": "^0.2.39",
"@types/benchmark": "^2.1.5",
"@total-typescript/ts-reset": "^0.6.1",
"@types/benchmark": "^2.1.5",
"@types/chai": "^4.3.17",
"@types/d3": "^7.4.3",
"@types/express": "^4.17.23",
+5 -5
View File
@@ -296,8 +296,8 @@ export class HostLobbyModal extends LitElement {
${typeof o === "string"
? translateText(`public_lobby.teams_${o}`)
: translateText("public_lobby.teams", {
num: o,
})}
num: o,
})}
</div>
</div>
`,
@@ -441,9 +441,9 @@ export class HostLobbyModal extends LitElement {
style="display: flex; flex-wrap: wrap; justify-content: center; gap: 12px;"
>
${renderUnitTypeOptions({
disabledUnits: this.disabledUnits,
toggleUnit: this.toggleUnit.bind(this),
})}
disabledUnits: this.disabledUnits,
toggleUnit: this.toggleUnit.bind(this),
})}
</div>
</div>
</div>
+9 -9
View File
@@ -276,16 +276,16 @@ export class LangSelector extends LitElement {
this.languageList.find((l) => l.code === this.currentLang) ??
(this.currentLang === "debug"
? {
code: "debug",
native: "Debug",
en: "Debug",
svg: "xx",
}
code: "debug",
native: "Debug",
en: "Debug",
svg: "xx",
}
: {
native: "English",
en: "English",
svg: "uk_us_flag",
});
native: "English",
en: "English",
svg: "uk_us_flag",
});
return html`
<div class="container__row">
+2 -2
View File
@@ -156,8 +156,8 @@ export class PublicLobby extends LitElement {
? typeof teamCount === "string"
? translateText(`public_lobby.teams_${teamCount}`)
: translateText("public_lobby.teams", {
num: teamCount ?? 0,
})
num: teamCount ?? 0,
})
: translateText("game_mode.ffa")}</span
>
<span
+4 -4
View File
@@ -244,8 +244,8 @@ export class UserSettingModal extends LitElement {
<button
class="w-1/2 text-center px-3 py-1 rounded-l
${this.settingsMode === "basic"
? "bg-white/10 text-white"
: "bg-transparent text-gray-400"}"
? "bg-white/10 text-white"
: "bg-transparent text-gray-400"}"
@click=${() => (this.settingsMode = "basic")}
>
${translateText("user_setting.tab_basic")}
@@ -253,8 +253,8 @@ export class UserSettingModal extends LitElement {
<button
class="w-1/2 text-center px-3 py-1 rounded-r
${this.settingsMode === "keybinds"
? "bg-white/10 text-white"
: "bg-transparent text-gray-400"}"
? "bg-white/10 text-white"
: "bg-transparent text-gray-400"}"
@click=${() => (this.settingsMode = "keybinds")}
>
${translateText("user_setting.tab_keybinds")}
+36 -36
View File
@@ -529,8 +529,8 @@ export class EventsDisplay extends LitElement implements Layer {
traitorDuration === 1
? translateText("events_display.duration_second")
: translateText("events_display.duration_seconds_plural", {
seconds: traitorDuration,
});
seconds: traitorDuration,
});
this.addEvent({
description: translateText("events_display.betrayal_description", {
@@ -768,11 +768,11 @@ export class EventsDisplay extends LitElement implements Layer {
})}
${!attack.retreating
? this.renderButton({
content: "❌",
onClick: () => this.emitCancelAttackIntent(attack.id),
className: "text-left flex-shrink-0",
disabled: attack.retreating,
})
content: "❌",
onClick: () => this.emitCancelAttackIntent(attack.id),
className: "text-left flex-shrink-0",
disabled: attack.retreating,
})
: html`<span class="flex-shrink-0 text-blue-400"
>(${translateText(
"events_display.retreating",
@@ -803,12 +803,12 @@ export class EventsDisplay extends LitElement implements Layer {
})}
${!landAttack.retreating
? this.renderButton({
content: "❌",
onClick: () =>
this.emitCancelAttackIntent(landAttack.id),
className: "text-left flex-shrink-0",
disabled: landAttack.retreating,
})
content: "❌",
onClick: () =>
this.emitCancelAttackIntent(landAttack.id),
className: "text-left flex-shrink-0",
disabled: landAttack.retreating,
})
: html`<span class="flex-shrink-0 text-blue-400"
>(${translateText(
"events_display.retreating",
@@ -840,11 +840,11 @@ export class EventsDisplay extends LitElement implements Layer {
})}
${!boat.retreating()
? this.renderButton({
content: "❌",
onClick: () => this.emitBoatCancelIntent(boat.id()),
className: "text-left flex-shrink-0",
disabled: boat.retreating(),
})
content: "❌",
onClick: () => this.emitBoatCancelIntent(boat.id()),
className: "text-left flex-shrink-0",
disabled: boat.retreating(),
})
: html`<span class="flex-shrink-0 text-blue-400"
>(${translateText(
"events_display.retreating",
@@ -1033,24 +1033,24 @@ export class EventsDisplay extends LitElement implements Layer {
>
${event.focusID
? this.renderButton({
content: this.getEventDescription(event),
onClick: () => {
event.focusID &&
content: this.getEventDescription(event),
onClick: () => {
event.focusID &&
this.emitGoToPlayerEvent(event.focusID);
},
className: "text-left",
})
},
className: "text-left",
})
: event.unitView
? this.renderButton({
content: this.getEventDescription(event),
onClick: () => {
event.unitView &&
content: this.getEventDescription(event),
onClick: () => {
event.unitView &&
this.emitGoToUnitEvent(
event.unitView,
);
},
className: "text-left",
})
},
className: "text-left",
})
: this.getEventDescription(event)}
<!-- Events with buttons (Alliance requests) -->
${event.buttons
@@ -1061,12 +1061,12 @@ export class EventsDisplay extends LitElement implements Layer {
<button
class="inline-block px-3 py-1 text-white rounded text-md md:text-sm cursor-pointer transition-colors duration-300
${btn.className.includes("btn-info")
? "bg-blue-500 hover:bg-blue-600"
: btn.className.includes(
"btn-gray",
)
? "bg-gray-500 hover:bg-gray-600"
: "bg-green-600 hover:bg-green-700"}"
? "bg-blue-500 hover:bg-blue-600"
: btn.className.includes(
"btn-gray",
)
? "bg-gray-500 hover:bg-gray-600"
: "bg-green-600 hover:bg-green-700"}"
@click=${() => {
btn.action();
if (!btn.preventClose) {
+3 -3
View File
@@ -351,9 +351,9 @@ export class PlayerPanel extends LitElement implements Layer {
>
${other.allies().length > 0
? other
.allies()
.map((p) => p.name())
.join(", ")
.allies()
.map((p) => p.name())
.join(", ")
: translateText("player_panel.none")}
</div>
</div>
+2 -2
View File
@@ -374,8 +374,8 @@ export class SettingsModal extends LitElement implements Layer {
${this.userSettings.performanceOverlay()
? translateText("user_setting.performance_overlay_enabled")
: translateText(
"user_setting.performance_overlay_disabled",
)}
"user_setting.performance_overlay_disabled",
)}
</div>
</div>
<div class="text-sm text-slate-400">
@@ -353,12 +353,12 @@ export class StructureIconsLayer implements Layer {
const shape = STRUCTURE_SHAPES[structureType];
const texture = shape
? this.createIcon(
unit.owner(),
structureType,
isConstruction,
shape,
renderIcon,
)
unit.owner(),
structureType,
isConstruction,
shape,
renderIcon,
)
: PIXI.Texture.EMPTY;
this.textureCache.set(cacheKey, texture);
+7 -7
View File
@@ -57,13 +57,13 @@ export async function createGameRunner(
const nations = gameStart.config.disableNPCs
? []
: gameMap.manifest.nations.map(
(n) =>
new Nation(
new Cell(n.coordinates[0], n.coordinates[1]),
n.strength,
new PlayerInfo(n.name, PlayerType.FakeHuman, null, random.nextID()),
),
);
(n) =>
new Nation(
new Cell(n.coordinates[0], n.coordinates[1]),
n.strength,
new PlayerInfo(n.name, PlayerType.FakeHuman, null, random.nextID()),
),
);
const game: Game = createGame(
humans,
+2 -2
View File
@@ -455,8 +455,8 @@ export class FakeHumanExecution implements Execution {
const tiles =
type === UnitType.Port
? Array.from(this.player.borderTiles()).filter((t) =>
this.mg.isOceanShore(t),
)
this.mg.isOceanShore(t),
)
: Array.from(this.player.tiles());
if (tiles.length === 0) return null;
return this.random.randElement(tiles);
+3 -3
View File
@@ -43,9 +43,9 @@ export class RailroadExecution implements Execution {
railType:
tiles.length > 0
? this.computeExtremityDirection(
tiles[tiles.length - 1],
tiles[tiles.length - 2],
)
tiles[tiles.length - 1],
tiles[tiles.length - 2],
)
: RailType.VERTICAL,
});
}
+10 -10
View File
@@ -11,19 +11,19 @@ export enum PathFindResultType {
}
export type AStarResult<NodeType> =
| {
type: PathFindResultType.NextTile;
node: NodeType;
}
type: PathFindResultType.NextTile;
node: NodeType;
}
| {
type: PathFindResultType.Pending;
}
type: PathFindResultType.Pending;
}
| {
type: PathFindResultType.Completed;
node: NodeType;
}
type: PathFindResultType.Completed;
node: NodeType;
}
| {
type: PathFindResultType.PathNotFound;
};
type: PathFindResultType.PathNotFound;
};
export type Point = {
x: number;
+3 -3
View File
@@ -11,9 +11,9 @@ import { PersistentIdSchema } from "../core/Schemas";
type TokenVerificationResult =
| {
persistentId: string;
claims: TokenPayload | null;
}
persistentId: string;
claims: TokenPayload | null;
}
| false;
export async function verifyClientToken(
@@ -63,14 +63,14 @@ async function handleJoinMessage(
): Promise<
| undefined
| {
success: true;
}
success: true;
}
| {
success: false;
code: 1002;
description: string;
error?: string;
reason:
success: false;
code: 1002;
description: string;
error?: string;
reason:
| "ClientJoinMessageSchema"
| "Flag invalid"
| "Flag restricted"
@@ -80,20 +80,20 @@ async function handleJoinMessage(
| "Pattern restricted"
| "Pattern unlisted"
| "Unauthorized";
}
}
| {
success: false;
code: 1011;
reason: "Internal server error";
error: string;
description: string;
}
success: false;
code: 1011;
reason: "Internal server error";
error: string;
description: string;
}
> {
const forwarded = req.headers["x-forwarded-for"];
const ip = Array.isArray(forwarded)
? forwarded[0]
: // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
forwarded || req.socket.remoteAddress || "unknown";
forwarded || req.socket.remoteAddress || "unknown";
try {
// Parse and handle client messages
+92 -92
View File
@@ -111,13 +111,13 @@ export default async (env, argv) => {
// Add optimization for HTML
minify: isProduction
? {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
}
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
}
: false,
}),
new webpack.DefinePlugin({
@@ -160,91 +160,91 @@ export default async (env, argv) => {
devServer: isProduction
? {}
: {
devMiddleware: { writeToDisk: true },
static: {
directory: path.join(__dirname, "static"),
},
historyApiFallback: true,
compress: true,
port: 9000,
proxy: [
// WebSocket proxies
{
context: ["/socket"],
target: "ws://localhost:3000",
ws: true,
changeOrigin: true,
logLevel: "debug",
},
// Worker WebSocket proxies - using direct paths without /socket suffix
{
context: ["/w0"],
target: "ws://localhost:3001",
ws: true,
secure: false,
changeOrigin: true,
logLevel: "debug",
},
{
context: ["/w1"],
target: "ws://localhost:3002",
ws: true,
secure: false,
changeOrigin: true,
logLevel: "debug",
},
{
context: ["/w2"],
target: "ws://localhost:3003",
ws: true,
secure: false,
changeOrigin: true,
logLevel: "debug",
},
// Worker proxies for HTTP requests
{
context: ["/w0"],
target: "http://localhost:3001",
pathRewrite: { "^/w0": "" },
secure: false,
changeOrigin: true,
logLevel: "debug",
},
{
context: ["/w1"],
target: "http://localhost:3002",
pathRewrite: { "^/w1": "" },
secure: false,
changeOrigin: true,
logLevel: "debug",
},
{
context: ["/w2"],
target: "http://localhost:3003",
pathRewrite: { "^/w2": "" },
secure: false,
changeOrigin: true,
logLevel: "debug",
},
// Original API endpoints
{
context: [
"/api/env",
"/api/game",
"/api/public_lobbies",
"/api/join_game",
"/api/start_game",
"/api/create_game",
"/api/archive_singleplayer_game",
"/api/auth/callback",
"/api/auth/discord",
"/api/kick_player",
],
target: "http://localhost:3000",
secure: false,
changeOrigin: true,
},
],
devMiddleware: { writeToDisk: true },
static: {
directory: path.join(__dirname, "static"),
},
historyApiFallback: true,
compress: true,
port: 9000,
proxy: [
// WebSocket proxies
{
context: ["/socket"],
target: "ws://localhost:3000",
ws: true,
changeOrigin: true,
logLevel: "debug",
},
// Worker WebSocket proxies - using direct paths without /socket suffix
{
context: ["/w0"],
target: "ws://localhost:3001",
ws: true,
secure: false,
changeOrigin: true,
logLevel: "debug",
},
{
context: ["/w1"],
target: "ws://localhost:3002",
ws: true,
secure: false,
changeOrigin: true,
logLevel: "debug",
},
{
context: ["/w2"],
target: "ws://localhost:3003",
ws: true,
secure: false,
changeOrigin: true,
logLevel: "debug",
},
// Worker proxies for HTTP requests
{
context: ["/w0"],
target: "http://localhost:3001",
pathRewrite: { "^/w0": "" },
secure: false,
changeOrigin: true,
logLevel: "debug",
},
{
context: ["/w1"],
target: "http://localhost:3002",
pathRewrite: { "^/w1": "" },
secure: false,
changeOrigin: true,
logLevel: "debug",
},
{
context: ["/w2"],
target: "http://localhost:3003",
pathRewrite: { "^/w2": "" },
secure: false,
changeOrigin: true,
logLevel: "debug",
},
// Original API endpoints
{
context: [
"/api/env",
"/api/game",
"/api/public_lobbies",
"/api/join_game",
"/api/start_game",
"/api/create_game",
"/api/archive_singleplayer_game",
"/api/auth/callback",
"/api/auth/discord",
"/api/kick_player",
],
target: "http://localhost:3000",
secure: false,
changeOrigin: true,
},
],
},
};
};