refactor: separate matchers

This commit is contained in:
wancat committed 2024-03-07 00:25:50 +08:00
1 parent 8280f7073d
commit e83d913852
10 files changed
+114 -92

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
{
"name": "@linux-odyssey/game",
"version": "1.0.0",
"main": "dist/index.ts",
"license": "MIT",
"scripts": {
"build": "tsc -b"
},
"dependencies": {}
}
-73
View File
@@ -1,73 +0,0 @@
/* eslint-disable max-classes-per-file */
import { Command } from './command'
import { Matcher } from './matcher'
export class CommandMatcher implements Matcher {
private matcher: RegExp
constructor(pattern: string, args?: string) {
this.matcher = new RegExp(pattern, args)
}
match(command: Partial<Command>): boolean {
return !!command.command && this.matcher.test(command.command)
}
}
export class ErrorMatcher implements Matcher {
private matcher?: RegExp
constructor(errorPattern?: string) {
if (errorPattern) {
this.matcher = new RegExp(errorPattern)
}
}
match(command: Partial<Command>): boolean {
if (!this.matcher) {
return !command.error
}
return this.matcher.test(command.error || '')
}
}
export class PwdMatcher implements Matcher {
constructor(private pwd: string) {}
match(command: Partial<Command>): boolean {
return command.pwd === this.pwd
}
}
export class OutputMatcher implements Matcher {
private matcher: RegExp
constructor(pattern: string, args?: string) {
this.matcher = new RegExp(pattern, args)
}
match(command: Partial<Command>): boolean {
return !!command.output && this.matcher.test(command.output.trim())
}
}
export interface ICondition {
command?: string
output?: string
error?: string
pwd?: string
}
export class Condition {
private matchers: Matcher[] = []
constructor({ command, output, error, pwd }: ICondition) {
if (command) this.matchers.push(new CommandMatcher(command))
if (output) this.matchers.push(new OutputMatcher(output))
if (pwd) this.matchers.push(new PwdMatcher(pwd))
this.matchers.push(new ErrorMatcher(error)) // always check unexpected error
}
match(command: Partial<Command>): boolean {
return this.matchers.every((matcher) => {
return matcher.match(command)
})
}
}
@@ -0,0 +1,13 @@
import { Command } from '../command.js'
import { Matcher } from './matcher.js'
export class CommandMatcher implements Matcher {
private matcher: RegExp
constructor(command: string, flags?: string) {
this.matcher = new RegExp(command, flags)
}
match(command: Partial<Command>): boolean {
return !!command.command && this.matcher.test(command.command)
}
}
+30
View File
@@ -0,0 +1,30 @@
import { Command } from '../command.js'
import { PwdMatcher } from './pwdMatcher.js'
import { CommandMatcher } from './commandMatcher.js'
import { ErrorMatcher } from './errorMatcher.js'
import { Matcher } from './matcher.js'
import { OutputMatcher } from './outputMatcher.js'
export interface ICondition {
command?: string
output?: string
error?: string
pwd?: string
}
export class Condition {
private matchers: Matcher[] = []
constructor({ command, output, error, pwd }: ICondition) {
if (command) this.matchers.push(new CommandMatcher(command))
if (output) this.matchers.push(new OutputMatcher(output))
if (pwd) this.matchers.push(new PwdMatcher(pwd))
this.matchers.push(new ErrorMatcher(error)) // always check unexpected error
}
match(command: Partial<Command>): boolean {
return this.matchers.every((matcher) => {
return matcher.match(command)
})
}
}
@@ -0,0 +1,18 @@
import { Matcher } from './matcher.js'
import { Command } from '../command.js'
export class ErrorMatcher implements Matcher {
private matcher?: RegExp
constructor(errorPattern?: string) {
if (errorPattern) {
this.matcher = new RegExp(errorPattern)
}
}
match(command: Partial<Command>): boolean {
if (!this.matcher) {
return !command.error
}
return this.matcher.test(command.error || '')
}
}
@@ -1,4 +1,4 @@
import { Command } from './command'
import { Command } from '../command.js'
export interface Matcher {
match(command: Partial<Command>): boolean
@@ -0,0 +1,13 @@
import { Command } from '../command.js'
import { Matcher } from './matcher.js'
export class OutputMatcher implements Matcher {
private matcher: RegExp
constructor(pattern: string, args?: string) {
this.matcher = new RegExp(pattern, args)
}
match(command: Partial<Command>): boolean {
return !!command.output && this.matcher.test(command.output.trim())
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Command } from '../command.js'
import { Matcher } from './matcher.js'
export class PwdMatcher implements Matcher {
constructor(private pwd: string) {}
match(command: Partial<Command>): boolean {
return command.pwd === this.pwd
}
}
+11 -18
View File
@@ -1,23 +1,16 @@
import { test, expect } from '@jest/globals'
import {
CommandMatcher,
ErrorMatcher,
PwdMatcher,
OutputMatcher,
Condition,
} from '../src/condition'
import { Command } from '../src/command'
import { Condition } from '../src/condition/condition'
import { OutputMatcher } from '../src/condition/outputMatcher'
import { PwdMatcher } from '../src/condition/pwdMatcher'
import { CommandMatcher } from '../src/condition/commandMatcher'
import { ErrorMatcher } from '../src/condition/errorMatcher.js'
test('command match', () => {
const command: Command = {
command: 'echo start',
output: 'start',
error: '',
pwd: '/home/user',
}
const matcher = new CommandMatcher('^echo start$', 'i')
expect(matcher.match(command)).toBe(true)
const matcher = new CommandMatcher('^echo start$')
expect(matcher.match({ command: 'echo start' })).toBe(true)
expect(matcher.match({ command: 'echo start1' })).toBe(false)
// Currently not supported
expect(matcher.match({ command: 'echo "start"' })).toBe(false)
})
test('error matcher', () => {
@@ -50,7 +43,7 @@ test('output matcher', () => {
expect(matcher.match({ output: 'start\n' })).toBe(true)
})
test('condition match', () => {
test('condition match command', () => {
const condition = new Condition({
command: '^echo start$',
})
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"]
}