Skip to content

Commit 7e369a7

Browse files
committed
Refactor codebase to functional style
Convert function declarations to arrow functions across all source files (shared, client, server). Class methods left unchanged. - Replace imperative loops with map/filter/reduce/find - Convert let to const using functional patterns - Add parameter destructuring throughout - Reorder functions where needed (const not hoisted) - Add jsdom devDependency for DOM testing
1 parent 3cf08c3 commit 7e369a7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2398
-1951
lines changed

package-lock.json

Lines changed: 525 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@vitest/coverage-v8": "^4.1.0",
2626
"esbuild": "^0.27.4",
2727
"husky": "^9.1.7",
28+
"jsdom": "^29.0.0",
2829
"tsx": "^4.21.0",
2930
"typescript": "^5.7.0",
3031
"vitest": "^4.0.18",

src/client/audio.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,28 @@
66
let ctx: AudioContext | null = null;
77
let muted = false;
88

9-
export function isMuted(): boolean {
9+
export const isMuted = (): boolean => {
1010
return muted;
11-
}
11+
};
1212

13-
export function setMuted(m: boolean) {
13+
export const setMuted = (m: boolean) => {
1414
muted = m;
1515
// Persist preference
1616
try {
1717
localStorage.setItem('delta-v-mute', m ? '1' : '0');
1818
} catch {}
19-
}
19+
};
2020

21-
function getCtx(): AudioContext | null {
21+
const getCtx = (): AudioContext | null => {
2222
if (muted) return null;
2323
if (!ctx) {
2424
ctx = new AudioContext();
2525
}
2626
return ctx;
27-
}
27+
};
2828

2929
/** Resume audio context after user gesture (required by browsers). */
30-
export function initAudio() {
30+
export const initAudio = () => {
3131
// Load saved mute preference
3232
try {
3333
const saved = localStorage.getItem('delta-v-mute');
@@ -43,10 +43,10 @@ export function initAudio() {
4343
};
4444
document.addEventListener('click', resume);
4545
document.addEventListener('touchstart', resume);
46-
}
46+
};
4747

4848
/** Short blip for UI interactions (button clicks, selections). */
49-
export function playSelect() {
49+
export const playSelect = () => {
5050
const ac = getCtx();
5151
if (!ac) return;
5252
const osc = ac.createOscillator();
@@ -60,10 +60,10 @@ export function playSelect() {
6060
gain.gain.exponentialRampToValueAtTime(0.001, ac.currentTime + 0.1);
6161
osc.start(ac.currentTime);
6262
osc.stop(ac.currentTime + 0.1);
63-
}
63+
};
6464

6565
/** Confirm/submit sound — ascending tone. */
66-
export function playConfirm() {
66+
export const playConfirm = () => {
6767
const ac = getCtx();
6868
if (!ac) return;
6969
const osc = ac.createOscillator();
@@ -77,10 +77,10 @@ export function playConfirm() {
7777
gain.gain.exponentialRampToValueAtTime(0.001, ac.currentTime + 0.2);
7878
osc.start(ac.currentTime);
7979
osc.stop(ac.currentTime + 0.2);
80-
}
80+
};
8181

8282
/** Thruster sound for movement. */
83-
export function playThrust() {
83+
export const playThrust = () => {
8484
const ac = getCtx();
8585
if (!ac) return;
8686
const bufSize = ac.sampleRate * 0.3;
@@ -102,10 +102,10 @@ export function playThrust() {
102102
filter.connect(gain);
103103
gain.connect(ac.destination);
104104
src.start(ac.currentTime);
105-
}
105+
};
106106

107107
/** Laser/beam sound for combat. */
108-
export function playCombat() {
108+
export const playCombat = () => {
109109
const ac = getCtx();
110110
if (!ac) return;
111111
const osc = ac.createOscillator();
@@ -119,10 +119,10 @@ export function playCombat() {
119119
gain.gain.exponentialRampToValueAtTime(0.001, ac.currentTime + 0.35);
120120
osc.start(ac.currentTime);
121121
osc.stop(ac.currentTime + 0.35);
122-
}
122+
};
123123

124124
/** Explosion sound for ship destruction or detonation. */
125-
export function playExplosion() {
125+
export const playExplosion = () => {
126126
const ac = getCtx();
127127
if (!ac) return;
128128
const bufSize = ac.sampleRate * 0.5;
@@ -144,10 +144,10 @@ export function playExplosion() {
144144
filter.connect(gain);
145145
gain.connect(ac.destination);
146146
src.start(ac.currentTime);
147-
}
147+
};
148148

149149
/** Alert tone for phase changes. */
150-
export function playPhaseChange() {
150+
export const playPhaseChange = () => {
151151
const ac = getCtx();
152152
if (!ac) return;
153153
const osc = ac.createOscillator();
@@ -171,10 +171,10 @@ export function playPhaseChange() {
171171
gain2.gain.exponentialRampToValueAtTime(0.001, ac.currentTime + 0.25);
172172
osc2.start(ac.currentTime + 0.12);
173173
osc2.stop(ac.currentTime + 0.25);
174-
}
174+
};
175175

176176
/** Warning beep for low timer. */
177-
export function playWarning() {
177+
export const playWarning = () => {
178178
const ac = getCtx();
179179
if (!ac) return;
180180
// Two short beeps
@@ -191,10 +191,10 @@ export function playWarning() {
191191
osc.start(t);
192192
osc.stop(t + 0.1);
193193
}
194-
}
194+
};
195195

196196
/** Victory fanfare. */
197-
export function playVictory() {
197+
export const playVictory = () => {
198198
const ac = getCtx();
199199
if (!ac) return;
200200
const notes = [523, 659, 784, 1047]; // C5, E5, G5, C6
@@ -211,10 +211,10 @@ export function playVictory() {
211211
osc.start(t);
212212
osc.stop(t + 0.3);
213213
});
214-
}
214+
};
215215

216216
/** Defeat sound. */
217-
export function playDefeat() {
217+
export const playDefeat = () => {
218218
const ac = getCtx();
219219
if (!ac) return;
220220
const notes = [400, 350, 300, 200]; // Descending
@@ -231,4 +231,4 @@ export function playDefeat() {
231231
osc.start(t);
232232
osc.stop(t + 0.35);
233233
});
234-
}
234+
};

src/client/game-client-ai-flow.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ export type AIActionPlan =
4343
aiPlayer: number;
4444
};
4545

46-
function buildAIOrdnanceLogEntries(state: GameState, launches: OrdnanceLaunch[]): string[] {
46+
const buildAIOrdnanceLogEntries = (state: GameState, launches: OrdnanceLaunch[]): string[] => {
4747
return launches.map((launch) => {
4848
const ship = state.ships.find((candidate) => candidate.id === launch.shipId);
4949
const name = ship ? (SHIP_STATS[ship.type]?.name ?? ship.type) : launch.shipId;
5050
return `AI: ${name} launched ${launch.ordnanceType}`;
5151
});
52-
}
52+
};
5353

54-
export function deriveAIActionPlan(
54+
export const deriveAIActionPlan = (
5555
state: GameState | null,
5656
playerId: number,
5757
map: SolarSystemMap,
@@ -61,7 +61,7 @@ export function deriveAIActionPlan(
6161
ordnance: aiOrdnance,
6262
combat: aiCombat,
6363
},
64-
): AIActionPlan {
64+
): AIActionPlan => {
6565
if (!state || state.phase === 'gameOver') {
6666
return { kind: 'none' };
6767
}
@@ -115,4 +115,4 @@ export function deriveAIActionPlan(
115115
kind: 'transition',
116116
aiPlayer,
117117
};
118-
}
118+
};

src/client/game-client-briefing.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ export interface BriefingLogEntry {
66
cssClass: string;
77
}
88

9-
function getBriefingCssClass(line: string): string {
9+
const getBriefingCssClass = (line: string): string => {
1010
if (line.startsWith('Objective: Escape') || line.startsWith('Objective: Get') || line.startsWith('Objective: Land')) {
1111
return 'log-landed';
1212
}
1313
if (line.startsWith('Objective: Inspect') || line.startsWith('Objective: Destroy')) {
1414
return 'log-damage';
1515
}
1616
return '';
17-
}
17+
};
1818

19-
export function deriveScenarioBriefingEntries(state: GameState, playerId: number): BriefingLogEntry[] {
19+
export const deriveScenarioBriefingEntries = (state: GameState, playerId: number): BriefingLogEntry[] => {
2020
return getScenarioBriefingLines(state, playerId).map((line) => ({
2121
text: line,
2222
cssClass: getBriefingCssClass(line),
2323
}));
24-
}
24+
};

src/client/game-client-burn.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ export type BurnChangePlan =
1010
clearOverload: boolean;
1111
};
1212

13-
export function deriveBurnChangePlan(
13+
export const deriveBurnChangePlan = (
1414
state: GameState | null,
1515
selectedShipId: string | null,
1616
direction: number,
1717
currentBurn: number | null,
18-
): BurnChangePlan {
18+
): BurnChangePlan => {
1919
if (!state) {
2020
return { kind: 'noop' };
2121
}
@@ -52,4 +52,4 @@ export function deriveBurnChangePlan(
5252
nextBurn: currentBurn === direction ? null : direction,
5353
clearOverload: currentBurn !== direction,
5454
};
55-
}
55+
};

0 commit comments

Comments
 (0)