green: load game spec via dynamic TS import
loadGame now imports content/games/<id>/spec.ts at runtime and returns its exported `spec`. The string-calc kata gets a typed spec.ts holding the seven step ids in order. Bun resolves the path relative to src/, no build step needed. Path traversal isn't validated yet; the next red will assert that an unknown or unsafe id throws cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2 files changed · +16 −1
content/games/string-calc/spec.ts
+14
−0
| @@ -0,0 +1,14 @@ | ||
| 1 | +import type { Game } from "../../../src/games"; | |
| 2 | + | |
| 3 | +export const spec: Game = { | |
| 4 | + id: "string-calc", | |
| 5 | + steps: [ | |
| 6 | + { id: "empty" }, | |
| 7 | + { id: "single-number" }, | |
| 8 | + { id: "two-numbers" }, | |
| 9 | + { id: "n-numbers" }, | |
| 10 | + { id: "newline-separator" }, | |
| 11 | + { id: "custom-separator" }, | |
| 12 | + { id: "negatives-throw" }, | |
| 13 | + ], | |
| 14 | +}; | |
src/games.ts
+2
−1
| @@ -8,5 +8,6 @@ export interface Game { | ||
| 8 | 8 | } |
| 9 | 9 | |
| 10 | 10 | export async function loadGame(id: string): Promise<Game> { |
| 11 | - return { id, steps: [] }; | |
| 11 | + const mod = await import(`../content/games/${id}/spec.ts`); | |
| 12 | + return mod.spec as Game; | |
| 12 | 13 | } |