From 77fe2d37b3639019fbcaf9b750652b1b7578494a Mon Sep 17 00:00:00 2001 From: wancat Date: Fri, 8 Mar 2024 00:38:49 +0800 Subject: [PATCH] feat: create stage --- packages/game/src/Stage.ts | 18 +++++++++++++ packages/game/src/condition/CommandMatcher.ts | 4 +-- packages/game/src/condition/Condition.ts | 4 +-- packages/game/src/condition/ErrorMatcher.ts | 4 +-- packages/game/src/condition/Matcher.ts | 4 +-- packages/game/src/condition/NotMatcher.ts | 4 +-- packages/game/src/condition/OrMatcher.ts | 4 +-- packages/game/src/condition/OutputMatcher.ts | 4 +-- packages/game/src/condition/PwdMatcher.ts | 4 +-- packages/game/src/types.ts | 10 ++++++-- packages/game/test/stage.test.ts | 25 +++++++++++++++++++ 11 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 packages/game/src/Stage.ts create mode 100644 packages/game/test/stage.test.ts diff --git a/packages/game/src/Stage.ts b/packages/game/src/Stage.ts new file mode 100644 index 0000000..7517dc9 --- /dev/null +++ b/packages/game/src/Stage.ts @@ -0,0 +1,18 @@ +import { IStage, ICommand } from './types' +import { Condition } from './condition/Condition' + +export class Stage { + id: string + name: string + condition: Condition + + constructor({ id, name, condition }: IStage) { + this.id = id + this.name = name + this.condition = new Condition(condition) + } + + satisfies(command: ICommand): boolean { + return this.condition.match(command) + } +} diff --git a/packages/game/src/condition/CommandMatcher.ts b/packages/game/src/condition/CommandMatcher.ts index 1387403..3f71bcd 100644 --- a/packages/game/src/condition/CommandMatcher.ts +++ b/packages/game/src/condition/CommandMatcher.ts @@ -1,4 +1,4 @@ -import { Command } from '../types.js' +import { ICommand } from '../types.js' import { Matcher } from './Matcher.js' export class CommandMatcher implements Matcher { @@ -7,7 +7,7 @@ export class CommandMatcher implements Matcher { this.matcher = new RegExp(command, flags) } - match(command: Command): boolean { + match(command: ICommand): boolean { return !!command.command && this.matcher.test(command.command) } } diff --git a/packages/game/src/condition/Condition.ts b/packages/game/src/condition/Condition.ts index fc8aea4..82c6c57 100644 --- a/packages/game/src/condition/Condition.ts +++ b/packages/game/src/condition/Condition.ts @@ -1,5 +1,5 @@ import { - Command, + ICommand, ICondition, IFileExistenceChecker, FileExistenceInput, @@ -30,7 +30,7 @@ export class Condition { this.matchers.push(new ErrorMatcher(error)) // always check unexpected error } - match(command: Command): boolean { + match(command: ICommand): boolean { return this.matchers.every((matcher) => { return matcher.match(command) }) diff --git a/packages/game/src/condition/ErrorMatcher.ts b/packages/game/src/condition/ErrorMatcher.ts index b77a2a8..6fd1d15 100644 --- a/packages/game/src/condition/ErrorMatcher.ts +++ b/packages/game/src/condition/ErrorMatcher.ts @@ -1,5 +1,5 @@ import { Matcher } from './Matcher.js' -import { Command } from '../types.js' +import { ICommand } from '../types.js' export class ErrorMatcher implements Matcher { private matcher?: RegExp @@ -9,7 +9,7 @@ export class ErrorMatcher implements Matcher { } } - match(command: Command): boolean { + match(command: ICommand): boolean { if (!this.matcher) { return !command.error } diff --git a/packages/game/src/condition/Matcher.ts b/packages/game/src/condition/Matcher.ts index 862942a..0af7c33 100644 --- a/packages/game/src/condition/Matcher.ts +++ b/packages/game/src/condition/Matcher.ts @@ -1,5 +1,5 @@ -import { Command } from '../types.js' +import { ICommand } from '../types.js' export interface Matcher { - match(command: Command): boolean + match(command: ICommand): boolean } diff --git a/packages/game/src/condition/NotMatcher.ts b/packages/game/src/condition/NotMatcher.ts index f37f746..1e9a846 100644 --- a/packages/game/src/condition/NotMatcher.ts +++ b/packages/game/src/condition/NotMatcher.ts @@ -1,10 +1,10 @@ -import { Command } from '../types.js' +import { ICommand } from '../types.js' import { Matcher } from './Matcher.js' export class NotMatcher implements Matcher { constructor(private condition: Matcher) {} - match(command: Command): boolean { + match(command: ICommand): boolean { return !this.condition.match(command) } } diff --git a/packages/game/src/condition/OrMatcher.ts b/packages/game/src/condition/OrMatcher.ts index eb51286..70c2091 100644 --- a/packages/game/src/condition/OrMatcher.ts +++ b/packages/game/src/condition/OrMatcher.ts @@ -1,10 +1,10 @@ -import { Command } from '../types.js' +import { ICommand } from '../types.js' import { Matcher } from './Matcher.js' export class OrMatcher implements Matcher { constructor(private conditions: Matcher[]) {} - match(command: Command): boolean { + match(command: ICommand): boolean { return this.conditions.some((condition) => condition.match(command)) } } diff --git a/packages/game/src/condition/OutputMatcher.ts b/packages/game/src/condition/OutputMatcher.ts index 643c558..89aa9a2 100644 --- a/packages/game/src/condition/OutputMatcher.ts +++ b/packages/game/src/condition/OutputMatcher.ts @@ -1,4 +1,4 @@ -import { Command } from '../types.js' +import { ICommand } from '../types.js' import { Matcher } from './Matcher.js' export class OutputMatcher implements Matcher { @@ -7,7 +7,7 @@ export class OutputMatcher implements Matcher { this.matcher = new RegExp(pattern, args) } - match(command: Command): boolean { + match(command: ICommand): boolean { return !!command.output && this.matcher.test(command.output.trim()) } } diff --git a/packages/game/src/condition/PwdMatcher.ts b/packages/game/src/condition/PwdMatcher.ts index dac9c78..781a7c5 100644 --- a/packages/game/src/condition/PwdMatcher.ts +++ b/packages/game/src/condition/PwdMatcher.ts @@ -1,10 +1,10 @@ -import { Command } from '../types.js' +import { ICommand } from '../types.js' import { Matcher } from './Matcher.js' export class PwdMatcher implements Matcher { constructor(private pwd: string) {} - match(command: Command): boolean { + match(command: ICommand): boolean { return command.pwd === this.pwd } } diff --git a/packages/game/src/types.ts b/packages/game/src/types.ts index 4bcbb1a..52fff79 100644 --- a/packages/game/src/types.ts +++ b/packages/game/src/types.ts @@ -1,4 +1,4 @@ -export interface Command { +export interface ICommand { command?: string output?: string error?: string @@ -12,7 +12,7 @@ export interface ICondition { pwd?: string or?: ICondition[] not?: ICondition - files: FileExistenceInput[] + files?: FileExistenceInput[] } export enum FileType { @@ -32,3 +32,9 @@ export interface FileExistenceInput extends FileInput { export interface IFileExistenceChecker { exists(file: FileInput): Promise } + +export interface IStage { + id: string + name: string + condition: ICondition +} diff --git a/packages/game/test/stage.test.ts b/packages/game/test/stage.test.ts new file mode 100644 index 0000000..8fa1617 --- /dev/null +++ b/packages/game/test/stage.test.ts @@ -0,0 +1,25 @@ +import { test, expect } from '@jest/globals' +import { Stage } from '../src/Stage' + +test('check stage condition', () => { + const stage = new Stage({ + id: 'stage1', + name: 'List the files using `ls`', + condition: { + command: 'ls', + pwd: '/home/user', + }, + }) + expect( + stage.satisfies({ + command: 'ls', + pwd: '/home/user', + }) + ).toBe(true) + expect( + stage.satisfies({ + command: 'ls', + pwd: '/home/user/Downloads', + }) + ).toBe(false) +})