From 7e50c8e06c7bf45470d652014b760508472171ad Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Thu, 24 Apr 2025 18:10:47 +0800 Subject: [PATCH] refactor: remove condition tests and update file node interfaces in game session TODO: replace "folder" with "directory" --- packages/constants/tests/condition.test.ts | 13 --------- packages/file-graph/src/index.ts | 4 +-- packages/game/src/Session.ts | 12 ++++---- packages/game/src/schema/command.ts | 23 +++++++++++++++ packages/game/src/schema/index.ts | 12 ++------ .../src/api/controllers/commandController.ts | 28 ++++++++----------- 6 files changed, 46 insertions(+), 46 deletions(-) delete mode 100644 packages/constants/tests/condition.test.ts create mode 100644 packages/game/src/schema/command.ts diff --git a/packages/constants/tests/condition.test.ts b/packages/constants/tests/condition.test.ts deleted file mode 100644 index 60b388a..0000000 --- a/packages/constants/tests/condition.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { describe, it, expect } from '@jest/globals' -import { conditionSchema } from '../src/index.js' - -describe('parsing condition', () => { - it('should parse condition', () => { - const condition = { - command: ['^echo start$'], - output: ['^start$'], - } - const result = conditionSchema.safeParse(condition) - expect(result.error).toBeUndefined() - }) -}) diff --git a/packages/file-graph/src/index.ts b/packages/file-graph/src/index.ts index 40b8ea8..d3f4a64 100644 --- a/packages/file-graph/src/index.ts +++ b/packages/file-graph/src/index.ts @@ -2,9 +2,9 @@ export { default as File, FileObject } from './file.js' export { default as FileNode } from './fileNode.js' export { default as FileGraph, Event } from './fileGraph.js' -export interface INode { +export interface IFileNode { path: string type: string discovered: boolean - children?: INode[] + children?: IFileNode[] } diff --git a/packages/game/src/Session.ts b/packages/game/src/Session.ts index 4b5c088..011e80e 100644 --- a/packages/game/src/Session.ts +++ b/packages/game/src/Session.ts @@ -1,4 +1,4 @@ -import { FileGraph, INode } from '@linux-odyssey/file-graph' +import { FileGraph, FileNode, IFileNode } from '@linux-odyssey/file-graph' import { Quest } from './Quest' import { IQuest, @@ -15,13 +15,15 @@ export class GameSession { private graph: FileGraph constructor( - { completedEvents, graph }: ISession, + { completedEvents, graph }: Partial, quest: IQuest, checker: IFileExistenceChecker ) { - this.completed = completedEvents + this.completed = completedEvents || [] this.quest = new Quest(quest, checker) - this.graph = new FileGraph(graph) + this.graph = new FileGraph( + graph ?? new FileNode({ path: '/', type: 'root', discovered: false }) + ) } get completedEvents() { @@ -56,7 +58,7 @@ export class GameSession { return this.quest.getTasks(this.completed) } - getGraph(): INode { + getGraph(): IFileNode { return this.graph } } diff --git a/packages/game/src/schema/command.ts b/packages/game/src/schema/command.ts new file mode 100644 index 0000000..02231d2 --- /dev/null +++ b/packages/game/src/schema/command.ts @@ -0,0 +1,23 @@ +import { z } from 'zod' + +const fileSchema = z.object({ + path: z.string(), + type: z.enum(['file', 'directory']), + discovered: z.boolean(), +}) + +export const commandParamsSchema = z.object({ + discover: fileSchema.array().optional(), +}) + +export type ICommandParams = z.infer + +export const commandSchema = z.object({ + command: z.string().optional(), + output: z.string().optional(), + error: z.string().optional(), + pwd: z.string().optional(), + params: commandParamsSchema.optional(), +}) + +export type ICommand = z.infer diff --git a/packages/game/src/schema/index.ts b/packages/game/src/schema/index.ts index 783c5c9..46a5859 100644 --- a/packages/game/src/schema/index.ts +++ b/packages/game/src/schema/index.ts @@ -1,4 +1,4 @@ -import { INode } from '@linux-odyssey/file-graph' +import { IFileNode } from '@linux-odyssey/file-graph' export * from './condition.js' export * from './stage.js' @@ -6,17 +6,11 @@ export * from './requirements.js' export * from './response.js' export * from './quest.js' export * from './exception.js' - -export interface ICommand { - command?: string - output?: string - error?: string - pwd?: string -} +export * from './command.js' export interface ISession { completedEvents: string[] - graph: INode + graph: IFileNode } export interface ITask { diff --git a/server/src/api/controllers/commandController.ts b/server/src/api/controllers/commandController.ts index 68cd71e..2784af4 100644 --- a/server/src/api/controllers/commandController.ts +++ b/server/src/api/controllers/commandController.ts @@ -1,6 +1,5 @@ -import { GameSession } from '@linux-odyssey/game' +import { GameSession, commandSchema } from '@linux-odyssey/game' import { Command, Session } from '@linux-odyssey/models' -import { matchedData } from 'express-validator' import type { Request, Response } from 'express' import { pushToSession } from '../socket.js' import { finishSession } from '../../models/sessionManager.js' @@ -9,7 +8,7 @@ import { questManager } from '../../models/quest.js' import { CLIFileExistenceChecker } from '../../containers/cli.js' export const newCommand = asyncHandler(async (req: Request, res: Response) => { - const { command, pwd, output, error, params } = matchedData(req) + const command = commandSchema.parse(req.body) console.log('command', command) @@ -31,16 +30,6 @@ export const newCommand = asyncHandler(async (req: Request, res: Response) => { session.lastActivityAt = new Date() - const c = new Command({ - session, - command, - pwd, - output, - error, - }) - - await c.save() - const quest = await questManager.get(session.quest) if (!quest) { res.status(404).json({ message: 'quest not found' }) @@ -53,12 +42,17 @@ export const newCommand = asyncHandler(async (req: Request, res: Response) => { new CLIFileExistenceChecker() ) - const event = await gameSession.runCommand(c) + const event = await gameSession.runCommand(command) console.log('event', event) - if (event) { - c.stage = event - await c.save() + const c = new Command({ + ...command, + session: sessionId, + stage: event, + }) + + await c.save() + if (event) { session.completedEvents = gameSession.completedEvents if (gameSession.isFinished()) {