import { describe, expect, test } from "vitest" import { readFileSync } from "node:fs" import { resolve } from "node:path" import * as wilderness from "../src/game/wilderness.ts" import * as maze from "../src/game/maze.ts" import * as levelLinks from "../src/game/level-links.ts" describe("DRLG Export and Alias Guard (Issue #81)", () => { const getDrlgExports = (mod: Record): string[] => { return Object.keys(mod).filter((name) => name.startsWith("DRLG")) } test("src/game/wilderness.ts does not export fake Blizzard aliases", () => { const exports = getDrlgExports(wilderness as Record) expect(exports).not.toContain("DRLGROOMTILE_ComputeNeighborMask") expect(exports).not.toContain("DRLGROOMTILE_ApplyTransitions") // The genuine custom functions should remain exported as local names expect(typeof (wilderness as Record).computeNeighborMask).toBe("function") expect(typeof (wilderness as Record).applyGroundTransitions).toBe("function") }) test("src/game/wilderness.ts keeps single export of DRLGOUTDOORS_SpawnAct12Waypoint", () => { const exports = getDrlgExports(wilderness as Record) expect(exports).toContain("DRLGOUTDOORS_SpawnAct12Waypoint") expect(typeof wilderness.DRLGOUTDOORS_SpawnAct12Waypoint).toBe("function") }) test("src/game/level-links.ts does not export duplicate DRLGOUTDOORS_SpawnAct12Waypoint", () => { const exports = getDrlgExports(levelLinks as Record) expect(exports).not.toContain("DRLGOUTDOORS_SpawnAct12Waypoint") expect(exports).not.toContain("DRLGROOMTILE_ComputeNeighborMask") expect(exports).not.toContain("DRLGROOMTILE_ApplyTransitions") // findWaypointSpot remains exported as a local helper expect(typeof levelLinks.findWaypointSpot).toBe("function") }) test("src/game/maze.ts does not export fake Blizzard DRLG aliases", () => { const exports = getDrlgExports(maze as Record) expect(exports).not.toContain("DRLGROOMTILE_ComputeNeighborMask") expect(exports).not.toContain("DRLGROOMTILE_ApplyTransitions") expect(exports).not.toContain("DRLGOUTDOORS_SpawnAct12Waypoint") }) test("DRLGOUTDOORS_SpawnAct12Waypoint has at most ONE export across wilderness, maze, and level-links", () => { const allDrlgExports = [ ...getDrlgExports(wilderness as Record), ...getDrlgExports(maze as Record), ...getDrlgExports(levelLinks as Record), ] const waypointExports = allDrlgExports.filter((name) => name === "DRLGOUTDOORS_SpawnAct12Waypoint") expect(waypointExports).toHaveLength(1) }) test("Static source check: no fake DRLG export statements in source files", () => { const files = [ resolve(__dirname, "../src/game/wilderness.ts"), resolve(__dirname, "../src/game/maze.ts"), resolve(__dirname, "../src/game/level-links.ts"), ] for (const filePath of files) { const source = readFileSync(filePath, "utf-8") expect(source).not.toMatch(/export\s+(?:const|function|let|var)\s+DRLGROOMTILE_ComputeNeighborMask\b/) expect(source).not.toMatch(/export\s+(?:const|function|let|var)\s+DRLGROOMTILE_ApplyTransitions\b/) } // Ensure level-links.ts does not export DRLGOUTDOORS_SpawnAct12Waypoint const levelLinksSource = readFileSync(resolve(__dirname, "../src/game/level-links.ts"), "utf-8") expect(levelLinksSource).not.toMatch(/export\s+(?:const|function|let|var)\s+DRLGOUTDOORS_SpawnAct12Waypoint\b/) // Ensure wilderness.ts has doc comments clarifying custom web port algorithms const wildernessSource = readFileSync(resolve(__dirname, "../src/game/wilderness.ts"), "utf-8") expect(wildernessSource).toMatch(/NOT a Blizzard original[\s\S]*?function computeNeighborMask/) expect(wildernessSource).toMatch(/NOT a Blizzard original[\s\S]*?function applyGroundTransitions/) }) })