Skip to content

Commit 889e5a5

Browse files
author
DavidQ
committed
BUILD PR: centralize debug config helpers across main entry points.
1 parent 65a36ba commit 889e5a5

11 files changed

Lines changed: 202 additions & 311 deletions

File tree

docs/dev/CODEX_COMMANDS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
MODEL: GPT-5.3-codex
22
REASONING: high
33
COMMAND:
4-
Execute docs/pr/BUILD_PR_SHARED_EXTRACTION_29_HIGHSCORE_HELPERS_BATCH.md exactly.
4+
Execute docs/pr/BUILD_PR_SHARED_EXTRACTION_30_DEBUG_CONFIG_HELPERS_BATCH.md exactly.
55
Edit only listed files.
66
Create shared helper file.
77
Do not expand scope.
8-
Package to <project folder>/tmp/BUILD_PR_SHARED_EXTRACTION_29_HIGHSCORE_HELPERS_BATCH_delta.zip
8+
Package to <project folder>/tmp/BUILD_PR_SHARED_EXTRACTION_30_DEBUG_CONFIG_HELPERS_BATCH_delta.zip

docs/dev/COMMIT_COMMENT.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
BUILD PR: centralize high score helpers across games.
1+
BUILD PR: centralize debug config helpers across main entry points.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
high score helpers centralized
1+
debug config helpers centralized
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# BUILD_PR_SHARED_EXTRACTION_30_DEBUG_CONFIG_HELPERS_BATCH
2+
3+
## Purpose
4+
Centralize duplicated debug configuration helpers across game entry points into a shared utility.
5+
6+
## Single PR Purpose
7+
Normalize ONLY these helpers:
8+
9+
- parseBooleanFlag(value, fallback)
10+
- normalizeDebugMode(value, fallback = 'prod')
11+
- readStoredBoolean(key)
12+
- writeStoredBoolean(key, value)
13+
- isLocalDebugEnvironment(documentRef)
14+
- resolveDebugConfig(documentRef)
15+
16+
## Target Files
17+
1. games/Asteroids/main.js
18+
2. games/Breakout/main.js
19+
3. games/network_sample_a/main.js
20+
4. games/network_sample_b/main.js
21+
5. games/network_sample_c/main.js
22+
6. samples/Phase 12 - Demo Games/sample1205-multi-system/main.js
23+
24+
## Exact Files Allowed
25+
26+
### New shared file
27+
1. src/shared/utils/debugConfigUtils.js
28+
29+
### Consumers
30+
2. games/Asteroids/main.js
31+
3. games/Breakout/main.js
32+
4. games/network_sample_a/main.js
33+
5. games/network_sample_b/main.js
34+
6. games/network_sample_c/main.js
35+
7. samples/Phase 12 - Demo Games/sample1205-multi-system/main.js
36+
37+
## Shared Helper Creation
38+
Create:
39+
src/shared/utils/debugConfigUtils.js
40+
41+
Export exactly:
42+
- parseBooleanFlag
43+
- normalizeDebugMode
44+
- readStoredBoolean
45+
- writeStoredBoolean
46+
- isLocalDebugEnvironment
47+
- resolveDebugConfig
48+
49+
Use ONE existing implementation as source-of-truth.
50+
Do NOT merge logic.
51+
Do NOT change behavior.
52+
53+
## Consumer Changes
54+
For each consumer file:
55+
- remove local implementations of the 6 helpers
56+
- import from src/shared/utils/debugConfigUtils.js
57+
- preserve all existing logic and usage
58+
59+
## Constraints
60+
- no engine changes
61+
- no UI changes
62+
- no behavior changes
63+
- exact batch only
64+
65+
## Validation
66+
- helpers exist only in shared file
67+
- consumers import correctly
68+
- no local duplicates remain
69+
70+
## Non-Goals
71+
- no debug UI changes
72+
- no refactor beyond helper extraction

games/Asteroids/main.js

Lines changed: 8 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ main.js
77
import Engine from '../../src/engine/core/Engine.js';
88
import { InputService } from '../../src/engine/input/index.js';
99
import { Theme, ThemeTokens } from '../../src/engine/theme/index.js';
10+
import {
11+
parseBooleanFlag,
12+
normalizeDebugMode,
13+
readStoredBoolean,
14+
writeStoredBoolean,
15+
isLocalDebugEnvironment,
16+
resolveDebugConfig
17+
} from '../../src/shared/utils/debugConfigUtils.js';
1018
import { createSampleGameDevConsoleIntegration } from '../../tools/dev/devConsoleIntegration.js';
1119
import { createAsteroidsShowcaseDebugPlugin } from './debug/asteroidsShowcaseDebug.js';
1220
import AsteroidsGameScene from './game/AsteroidsGameScene.js';
@@ -20,105 +28,6 @@ function sanitizeText(value) {
2028
return typeof value === 'string' ? value.trim() : '';
2129
}
2230

23-
function parseBooleanFlag(value, fallback) {
24-
const normalized = sanitizeText(value).toLowerCase();
25-
if (!normalized) {
26-
return fallback;
27-
}
28-
if (normalized === '1' || normalized === 'true' || normalized === 'on' || normalized === 'yes') {
29-
return true;
30-
}
31-
if (normalized === '0' || normalized === 'false' || normalized === 'off' || normalized === 'no') {
32-
return false;
33-
}
34-
return fallback;
35-
}
36-
37-
function normalizeDebugMode(value, fallback = 'prod') {
38-
const normalized = sanitizeText(value).toLowerCase();
39-
if (normalized === 'dev' || normalized === 'qa' || normalized === 'prod') {
40-
return normalized;
41-
}
42-
return fallback;
43-
}
44-
45-
function readStoredBoolean(key) {
46-
if (!key || typeof globalThis.localStorage === 'undefined') {
47-
return null;
48-
}
49-
50-
try {
51-
const value = globalThis.localStorage.getItem(key);
52-
if (value === '1') {
53-
return true;
54-
}
55-
if (value === '0') {
56-
return false;
57-
}
58-
} catch {
59-
return null;
60-
}
61-
62-
return null;
63-
}
64-
65-
function writeStoredBoolean(key, value) {
66-
if (!key || typeof globalThis.localStorage === 'undefined') {
67-
return;
68-
}
69-
70-
try {
71-
globalThis.localStorage.setItem(key, value ? '1' : '0');
72-
} catch {
73-
// Ignore storage failures to keep startup resilient.
74-
}
75-
}
76-
77-
function isLocalDebugEnvironment(documentRef) {
78-
const protocol = sanitizeText(documentRef?.location?.protocol) || sanitizeText(globalThis?.location?.protocol);
79-
const hostname = sanitizeText(documentRef?.location?.hostname) || sanitizeText(globalThis?.location?.hostname);
80-
81-
if (protocol === 'file:') {
82-
return true;
83-
}
84-
85-
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';
86-
}
87-
88-
function resolveDebugConfig(documentRef) {
89-
const search = sanitizeText(documentRef?.location?.search) || sanitizeText(globalThis?.location?.search);
90-
const searchParams = new URLSearchParams(search);
91-
const queryMode = searchParams.get('debugMode');
92-
const queryEnabled = searchParams.get('debug');
93-
const queryRemember = searchParams.get('rememberDebug');
94-
const queryDemo = searchParams.get('debugDemo');
95-
const localDebugEnvironment = isLocalDebugEnvironment(documentRef);
96-
const rememberDebugState = parseBooleanFlag(queryRemember, false);
97-
const demoMode = parseBooleanFlag(queryDemo, false);
98-
const defaultMode = localDebugEnvironment
99-
? 'dev'
100-
: normalizeDebugMode(BUILD_DEBUG_MODE, 'prod');
101-
const debugMode = normalizeDebugMode(queryMode, demoMode ? 'qa' : defaultMode);
102-
const fallbackEnabled = (BUILD_DEBUG_ENABLED === true || localDebugEnvironment) && debugMode !== 'prod';
103-
const storedDebugEnabled = rememberDebugState && queryEnabled === null
104-
? readStoredBoolean(DEBUG_STATE_STORAGE_KEY)
105-
: null;
106-
const debugEnabled = demoMode
107-
? true
108-
: parseBooleanFlag(queryEnabled, storedDebugEnabled ?? fallbackEnabled);
109-
110-
if (rememberDebugState) {
111-
writeStoredBoolean(DEBUG_STATE_STORAGE_KEY, debugEnabled);
112-
}
113-
114-
return {
115-
debugMode,
116-
debugEnabled,
117-
rememberDebugState,
118-
demoMode
119-
};
120-
}
121-
12231
function applyDefaultDebugPreset(devConsoleIntegration, presetCommands) {
12332
if (!devConsoleIntegration || typeof devConsoleIntegration.executeCommand !== 'function') {
12433
return '';

games/breakout/main.js

Lines changed: 8 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ main.js
77
import Engine from '../../src/engine/core/Engine.js';
88
import { InputService } from '../../src/engine/input/index.js';
99
import { Theme, ThemeTokens } from '../../src/engine/theme/index.js';
10+
import {
11+
parseBooleanFlag,
12+
normalizeDebugMode,
13+
readStoredBoolean,
14+
writeStoredBoolean,
15+
isLocalDebugEnvironment,
16+
resolveDebugConfig,
17+
} from '../../src/shared/utils/debugConfigUtils.js';
1018
import { createSampleGameDevConsoleIntegration } from '../../tools/dev/devConsoleIntegration.js';
1119
import BreakoutScene from './game/BreakoutScene.js';
1220

@@ -19,105 +27,6 @@ function sanitizeText(value) {
1927
return typeof value === 'string' ? value.trim() : '';
2028
}
2129

22-
function parseBooleanFlag(value, fallback) {
23-
const normalized = sanitizeText(value).toLowerCase();
24-
if (!normalized) {
25-
return fallback;
26-
}
27-
if (normalized === '1' || normalized === 'true' || normalized === 'on' || normalized === 'yes') {
28-
return true;
29-
}
30-
if (normalized === '0' || normalized === 'false' || normalized === 'off' || normalized === 'no') {
31-
return false;
32-
}
33-
return fallback;
34-
}
35-
36-
function normalizeDebugMode(value, fallback = 'prod') {
37-
const normalized = sanitizeText(value).toLowerCase();
38-
if (normalized === 'dev' || normalized === 'qa' || normalized === 'prod') {
39-
return normalized;
40-
}
41-
return fallback;
42-
}
43-
44-
function readStoredBoolean(key) {
45-
if (!key || typeof globalThis.localStorage === 'undefined') {
46-
return null;
47-
}
48-
49-
try {
50-
const value = globalThis.localStorage.getItem(key);
51-
if (value === '1') {
52-
return true;
53-
}
54-
if (value === '0') {
55-
return false;
56-
}
57-
} catch {
58-
return null;
59-
}
60-
61-
return null;
62-
}
63-
64-
function writeStoredBoolean(key, value) {
65-
if (!key || typeof globalThis.localStorage === 'undefined') {
66-
return;
67-
}
68-
69-
try {
70-
globalThis.localStorage.setItem(key, value ? '1' : '0');
71-
} catch {
72-
// Ignore storage failures to preserve startup behavior.
73-
}
74-
}
75-
76-
function isLocalDebugEnvironment(documentRef) {
77-
const protocol = sanitizeText(documentRef?.location?.protocol) || sanitizeText(globalThis?.location?.protocol);
78-
const hostname = sanitizeText(documentRef?.location?.hostname) || sanitizeText(globalThis?.location?.hostname);
79-
80-
if (protocol === 'file:') {
81-
return true;
82-
}
83-
84-
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';
85-
}
86-
87-
function resolveDebugConfig(documentRef) {
88-
const search = sanitizeText(documentRef?.location?.search) || sanitizeText(globalThis?.location?.search);
89-
const searchParams = new URLSearchParams(search);
90-
const queryMode = searchParams.get('debugMode');
91-
const queryEnabled = searchParams.get('debug');
92-
const queryRemember = searchParams.get('rememberDebug');
93-
const queryDemo = searchParams.get('debugDemo');
94-
const localDebugEnvironment = isLocalDebugEnvironment(documentRef);
95-
const rememberDebugState = parseBooleanFlag(queryRemember, false);
96-
const demoMode = parseBooleanFlag(queryDemo, false);
97-
const defaultMode = localDebugEnvironment
98-
? 'dev'
99-
: normalizeDebugMode(BUILD_DEBUG_MODE, 'prod');
100-
const debugMode = normalizeDebugMode(queryMode, demoMode ? 'qa' : defaultMode);
101-
const fallbackEnabled = (BUILD_DEBUG_ENABLED === true || localDebugEnvironment) && debugMode !== 'prod';
102-
const storedDebugEnabled = rememberDebugState && queryEnabled === null
103-
? readStoredBoolean(DEBUG_STATE_STORAGE_KEY)
104-
: null;
105-
const debugEnabled = demoMode
106-
? true
107-
: parseBooleanFlag(queryEnabled, storedDebugEnabled ?? fallbackEnabled);
108-
109-
if (rememberDebugState) {
110-
writeStoredBoolean(DEBUG_STATE_STORAGE_KEY, debugEnabled);
111-
}
112-
113-
return {
114-
debugMode,
115-
debugEnabled,
116-
rememberDebugState,
117-
demoMode,
118-
};
119-
}
120-
12130
function applyDefaultDebugPreset(devConsoleIntegration) {
12231
if (!devConsoleIntegration || typeof devConsoleIntegration.executeCommand !== 'function') {
12332
return '';

games/network_sample_a/main.js

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ main.js
77
import Engine from "../../engine/core/Engine.js";
88
import { InputService } from "../../engine/input/index.js";
99
import { Theme, ThemeTokens } from "../../engine/theme/index.js";
10+
import { resolveDebugConfig } from "../../src/shared/utils/debugConfigUtils.js";
1011
import { createSampleGameDevConsoleIntegration } from "../../tools/dev/devConsoleIntegration.js";
1112
import { createNetworkSampleADebugPlugin } from "./debug/networkSampleADebug.js";
1213
import NetworkSampleAScene from "./game/NetworkSampleAScene.js";
@@ -17,30 +18,6 @@ function sanitizeText(value) {
1718
return typeof value === "string" ? value.trim() : "";
1819
}
1920

20-
function parseBooleanFlag(value, fallback) {
21-
const normalized = sanitizeText(value).toLowerCase();
22-
if (!normalized) {
23-
return fallback;
24-
}
25-
if (normalized === "1" || normalized === "true" || normalized === "on" || normalized === "yes") {
26-
return true;
27-
}
28-
if (normalized === "0" || normalized === "false" || normalized === "off" || normalized === "no") {
29-
return false;
30-
}
31-
return fallback;
32-
}
33-
34-
function resolveDebugConfig(documentRef) {
35-
const search = sanitizeText(documentRef?.location?.search) || sanitizeText(globalThis?.location?.search);
36-
const searchParams = new URLSearchParams(search);
37-
38-
return {
39-
debugMode: "dev",
40-
debugEnabled: parseBooleanFlag(searchParams.get("debug"), true)
41-
};
42-
}
43-
4421
function updateDebugUi(documentRef, integration, enabled) {
4522
const badge = documentRef?.getElementById?.("debugStateBadge") ?? null;
4623
const button = documentRef?.getElementById?.("openDebugPanelButton") ?? null;

0 commit comments

Comments
 (0)