Skip to content

Commit

Permalink
Merge branch 'master' into update-vitepress
Browse files Browse the repository at this point in the history
  • Loading branch information
MaikoTan committed Mar 8, 2024
2 parents 54d4044 + 39f5951 commit 97b4cfd
Show file tree
Hide file tree
Showing 12 changed files with 2,451 additions and 1,138 deletions.
1 change: 1 addition & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ ignorePatterns:
- packages/*/dist
- packages/*/coverage
- packages/*/docs
- external/**/*
48 changes: 25 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,34 @@
"test:html": "shx rm -rf coverage && c8 -r html yarn test"
},
"devDependencies": {
"@hamster-bot/eslint-config": "^1.0.1",
"@koishijs/plugin-database-memory": "^2.3.6",
"@koishijs/plugin-mock": "^2.6.4",
"@koishijs/vitepress": "^3.0.1",
"@types/chai": "^4.3.9",
"@types/mocha": "^10.0.3",
"@types/node": "^20.8.10",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
"@hamster-bot/eslint-config": "^1.0.5",
"@koishijs/plugin-database-memory": "^3.0.0",
"@koishijs/plugin-mock": "^2.6.5",
"@koishijs/vitepress": "^3.2.4",
"@types/chai": "^4.3.12",
"@types/mocha": "^10.0.6",
"@types/node": "^20.11.25",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"c8": "^8.0.1",
"chai": "^4.3.10",
"esbuild": "^0.19.5",
"chai": "^4.4.1",
"esbuild": "^0.20.1",
"esbuild-register": "^3.5.0",
"eslint": "^8.53.0",
"eslint": "^8.57.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-n": "^16.2.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-mocha": "^10.3.0",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-promise": "^6.1.1",
"jest-mock": "^29.7.0",
"koishi": "^4.15.4",
"koishi-plugin-puppeteer": "^3.7.0",
"mocha": "^10.2.0",
"prettier": "^3.0.3",
"sass": "^1.69.5",
"koishi": "^4.17.2",
"koishi-plugin-puppeteer": "^3.8.2",
"mocha": "^10.3.0",
"prettier": "^3.2.5",
"sass": "^1.71.1",
"shx": "^0.3.4",
"typescript": "^5.3.2",
"typescript": "^5.4.2",
"vitepress": "1.0.0-rc.45",
"yakumo": "^0.3.13",
"yakumo-esbuild": "^0.3.26",
Expand All @@ -58,8 +60,8 @@
"yakumo-publish": "^0.3.10",
"yakumo-publish-sync": "^0.3.3",
"yakumo-tsc": "^0.3.12",
"yakumo-upgrade": "^0.3.4",
"yakumo-upgrade": "^0.3.6",
"yakumo-version": "^0.3.4",
"yml-register": "^1.1.0"
"yml-register": "^1.2.5"
}
}
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"game"
],
"peerDependencies": {
"koishi": "^4.15.3"
"koishi": "^4.17.2"
},
"devDependencies": {
"@koishijs/canvas": "^0.2.0"
Expand Down
149 changes: 77 additions & 72 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
/* eslint-disable @typescript-eslint/no-namespace */
import type {} from '@koishijs/canvas'
import { Argv, Command, Context, Element, h, I18n, Plugin, Session, Schema } from 'koishi'

import type { Inject } from 'cordis'
import { Argv, Command, Context, Element, h, Plugin, Session, Schema } from 'koishi'

export interface VariationInstanceLike<T = any> {
export interface VariationInstanceLike<T = unknown> {
ctx: Context
config: T
}

export interface WordleVariation<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Config = any,
ConfigSchema extends Schema<Config> = Schema<Config>,
WordType extends any[] = string[],
WordType extends unknown[] = string[],
MoreUnitResult = WordType[number],
> extends Omit<Plugin.Object, 'Config' | 'apply'> {
command: string | Command
Config: ConfigSchema
locales?: Record<string, any>
locales?: Record<string, I18n.Store>
guessCount?: number
possibleUnitResults?: readonly MoreUnitResult[]
init?: (command: Command, cls: VariationInstanceLike<Config>) => void
Expand All @@ -25,7 +28,7 @@ export interface WordleVariation<
// Game logic and lifecycle
onGameStart?: (argv: Argv, cls: VariationInstanceLike<Config>) => Promise<void>
onGameEnd?: (argv: Argv, ctx: Context) => Promise<void>
handleInput?: <WordType extends any[] = string[]>(
handleInput?: <WordType extends unknown[] = string[]>(
input: string,
state: Wordle.WordleState<WordType>,
argv: Argv,
Expand All @@ -38,16 +41,16 @@ export namespace Wordle {
Active = 'active',
}

export interface WordleState<WordType extends any[] = string[]> {
export interface WordleState<WordType extends unknown[] = string[]> {
state?: GameState
currentWord: WordType
guessedWords?: VerificatedResult<any>[]
guessedWords?: VerificatedResult<unknown>[]
guessedCount?: number
}

export type UnitResultType = 'correct' | 'bad-position' | 'incorrect'

export interface UnitResult<MoreUnitResult, WordType extends any[] = string[]> {
export interface UnitResult<MoreUnitResult, WordType extends unknown[] = string[]> {
type: UnitResultType | MoreUnitResult
char: WordType[number]
}
Expand All @@ -59,9 +62,10 @@ export namespace Wordle {
}

export function defineVariation<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Config = any,
ConfigSchema extends Schema<Config> = Schema<Config>,
WordType extends any[] = string[],
WordType extends unknown[] = string[],
MoreUnitResult = string,
>(variation: WordleVariation<Config, ConfigSchema, WordType, MoreUnitResult>): Plugin.Constructor {
let command: Command
Expand Down Expand Up @@ -132,7 +136,7 @@ export function defineVariation<
// re-export koishi fields
name = variation.name
static Config = variation.Config
static inject = normalizeInject(variation.inject ?? variation.using)
static inject = normalizeInject(variation.inject)
static reusable = variation.reusable
static reactive = variation.reactive

Expand All @@ -141,6 +145,7 @@ export function defineVariation<
public config: Config,
) {
// define locales
// eslint-disable-next-line @typescript-eslint/no-var-requires
ctx.i18n.define('zh-CN', require('./locales/zh-CN'))
// register global command messages for this variation
ctx.i18n.define('zh-CN', {
Expand All @@ -161,83 +166,83 @@ export function defineVariation<
variation.init?.(command, this)
command.option('quit', '-q')

command.action(async (argv, word) => {
const { session } = argv
const state = sessionState.get(`${session.guildId}.${session.channelId}`)
if ((argv.options as any).quit) {
if (state?.state !== Wordle.GameState.Active) {
return session?.text('wordle.messages.not-started', [command.name])
.action(async (argv, word) => {
const { session } = argv
const state = sessionState.get(`${session.guildId}.${session.channelId}`)
if (argv.options.quit) {
if (state?.state !== Wordle.GameState.Active) {
return session?.text('wordle.messages.not-started', [command.name])
}
sessionState.delete(`${session.guildId}.${session.channelId}`)
variation.onGameEnd?.(argv, ctx)
return session?.text('wordle.messages.game-ended', [command.name, state.currentWord.join('')])
}
sessionState.delete(`${session.guildId}.${session.channelId}`)
variation.onGameEnd?.(argv, ctx)
return session?.text('wordle.messages.game-ended', [command.name, state.currentWord.join('')])
}

if (state?.state !== Wordle.GameState.Active && word) {
return session?.text('wordle.messages.not-started', [command.name])
}
if (state?.state === Wordle.GameState.Active) {
if (word) {
const result = await handleInput(word, state, argv, this)
const text: Element[] = []
switch (result.type) {
case 'bad-length':
text.push(h.text(session?.text('wordle.messages.bad-length')))
break
case 'invalid':
text.push(h.text(session?.text('wordle.messages.invalid')))
break
case 'correct':
text.push(h.text(session?.text('wordle.messages.correct')))
// Note: here we do not use `break` here as we need to render the result as well
// eslint-disable-next-line no-fallthrough
case 'incorrect':
text.push(await this.render(result.unitResults, state.guessedWords ?? [], session))
break
}
if (state?.state !== Wordle.GameState.Active && word) {
return session?.text('wordle.messages.not-started', [command.name])
}
if (state?.state === Wordle.GameState.Active) {
if (word) {
const result = await handleInput(word, state, argv, this)
const text: Element[] = []
switch (result.type) {
case 'bad-length':
text.push(h.text(session?.text('wordle.messages.bad-length')))
break
case 'invalid':
text.push(h.text(session?.text('wordle.messages.invalid')))
break
case 'correct':
text.push(h.text(session?.text('wordle.messages.correct')))
// Note: here we do not use `break` here as we need to render the result as well
// eslint-disable-next-line no-fallthrough
case 'incorrect':
text.push(await this.render(result.unitResults, state.guessedWords ?? [], session))
break
}

await session.send(text)
await session.send(text)

if (result.type === 'correct') {
if (result.type === 'correct') {
// game ended
sessionState.delete(`${session.guildId}.${session.channelId}`)
variation.onGameEnd?.(argv, ctx)
} else if (state.guessedCount >= variation.guessCount) {
await session.send(session?.text('wordle.messages.game-over', [state.currentWord.join('')]))
variation.onGameEnd?.(argv, ctx)
sessionState.delete(`${session.guildId}.${session.channelId}`)
} else if (result.type === 'incorrect') {
sessionState.set(`${session.guildId}.${session.channelId}`, {
state: Wordle.GameState.Active,
currentWord: state.currentWord,
guessedWords: [...(state.guessedWords ?? []), result],
guessedCount: state.guessedCount + 1,
})
sessionState.delete(`${session.guildId}.${session.channelId}`)
variation.onGameEnd?.(argv, ctx)
} else if (state.guessedCount >= variation.guessCount) {
await session.send(session?.text('wordle.messages.game-over', [state.currentWord.join('')]))
variation.onGameEnd?.(argv, ctx)
sessionState.delete(`${session.guildId}.${session.channelId}`)
} else if (result.type === 'incorrect') {
sessionState.set(`${session.guildId}.${session.channelId}`, {
state: Wordle.GameState.Active,
currentWord: state.currentWord,
guessedWords: [...(state.guessedWords ?? []), result],
guessedCount: state.guessedCount + 1,
})
}
} else {
return session?.text('wordle.messages.no-input', [command.name])
}
} else {
return session?.text('wordle.messages.no-input', [command.name])
}
} else {
// start a new game
variation.onGameStart?.(argv, this)
const currentWord = await this.getCurrentWord(argv, ctx)
sessionState.set(`${session.guildId}.${session.channelId}`, {
state: Wordle.GameState.Active,
currentWord,
guessedCount: 1,
})
await session.send(session?.text('wordle.messages.game-started', [command.name, variation.guessCount]))
}
})
variation.onGameStart?.(argv, this)
const currentWord = await this.getCurrentWord(argv, ctx)
sessionState.set(`${session.guildId}.${session.channelId}`, {
state: Wordle.GameState.Active,
currentWord,
guessedCount: 1,
})
await session.send(session?.text('wordle.messages.game-started', [command.name, variation.guessCount]))
}
})
}

getCurrentWord(argv: Argv, ctx: Context) {
return variation.getCurrentWord(argv, this)
}

async render(
word: Wordle.UnitResult<any>[],
guessedWords: Wordle.VerificatedResult[],
word: Wordle.UnitResult<unknown>[],
guessedWords: Wordle.VerificatedResult<unknown>[],
session: Session,
): Promise<Element> {
const width = word.length * 60 + 5 * (word.length + 1)
Expand Down
4 changes: 2 additions & 2 deletions packages/core/tests/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ describe('core', () => {
return 'hello'.split('')
},
})
;(wordle as any).inject = []
wordle.inject = []
wordle.prototype.render = async function (
word: Wordle.UnitResult<any>[],
word: Wordle.UnitResult<string>[],
guessedWords: Wordle.VerificatedResult[],
session: Session,
) {
Expand Down
2 changes: 1 addition & 1 deletion packages/reactle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@
"@koishijs/wordle": "^0.0.17"
},
"peerDependencies": {
"koishi": "^4.15.3"
"koishi": "^4.17.2"
}
}
1 change: 1 addition & 0 deletions packages/reactle/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default defineVariation<Config>({
command.option('random', '-r')
},
async getCurrentWord({ options }) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((options as any).random) {
return wordlist[Math.floor(Math.random() * wordlist.length)].split('')
}
Expand Down
6 changes: 3 additions & 3 deletions packages/reactle/tests/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ describe('reactle', () => {
app.plugin(mock)
app.plugin(memory)
// set getCurrentWord always return 'hello'
;(reactle as any).prototype.getCurrentWord = () => Promise.resolve(['h', 'e', 'l', 'l', 'o'])
;(reactle as any).inject = []
reactle.prototype.getCurrentWord = () => Promise.resolve(['h', 'e', 'l', 'l', 'o'])
reactle.inject = []
reactle.prototype.render = async function (
word: Wordle.UnitResult<any>[],
word: Wordle.UnitResult<string>[],
guessedWords: Wordle.VerificatedResult[],
session: Session,
) {
Expand Down
2 changes: 1 addition & 1 deletion packages/wordle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@
"@koishijs/wordle": "^0.0.17"
},
"peerDependencies": {
"koishi": "^4.15.3"
"koishi": "^4.17.2"
}
}
1 change: 1 addition & 0 deletions packages/wordle/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default defineVariation<Config>({
command.option('random', '-r')
},
async getCurrentWord({ options, session }, { ctx, config }) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((options as any).random) {
return getRandomWord().split('')
}
Expand Down
6 changes: 3 additions & 3 deletions packages/wordle/tests/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ describe('wordle', () => {
app.plugin(mock)
app.plugin(memory)
// set getCurrentWord always return 'hello'
;(wordle as any).prototype.getCurrentWord = () => Promise.resolve(['h', 'e', 'l', 'l', 'o'])
;(wordle as any).inject = []
wordle.prototype.getCurrentWord = () => Promise.resolve(['h', 'e', 'l', 'l', 'o'])
wordle.inject = []
wordle.prototype.render = async function (
word: Wordle.UnitResult<any>[],
word: Wordle.UnitResult<unknown>[],
guessedWords: Wordle.VerificatedResult[],
session: Session,
) {
Expand Down
Loading

0 comments on commit 97b4cfd

Please sign in to comment.