From d951031c5cc53b9705ba20d23a528a8109e17332 Mon Sep 17 00:00:00 2001 From: Shigma <1700011071@pku.edu.cn> Date: Tue, 25 Aug 2020 02:16:39 +0800 Subject: [PATCH 01/31] init mapping --- package.json | 3 ++- tsconfig.test.json | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tsconfig.test.json diff --git a/package.json b/package.json index f29f4548df..04007dbaeb 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "bump": "ts-node build/bump", "dep": "ts-node build/dep", "docs": "cd docs && yarn dev", - "test": "mocha --experimental-vm-modules --enable-source-maps", + "test": "cross-env TS_NODE_PROJECT=tsconfig.test.json mocha --experimental-vm-modules --enable-source-maps", "test:json": "c8 -r json yarn test", "test:lcov": "rimraf coverage && c8 -r lcov yarn test", "test:text": "c8 -r text yarn test", @@ -41,6 +41,7 @@ "cac": "^6.6.1", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", + "cross-env": "^7.0.2", "cross-spawn": "^7.0.3", "del": "^5.1.0", "eslint": "^7.7.0", diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000000..9f761ab605 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "paths": { + "koishi-plugin-*": ["packages/plugin-*/src"], + "koishi-adapter-*": ["packages/adapter-*/src"], + "koishi-*": ["packages/koishi-*/src"], + }, + }, +} \ No newline at end of file From b1ea76d2dfc43e4ba5852b52e1eeb03beeb36541 Mon Sep 17 00:00:00 2001 From: jjyyxx Date: Tue, 25 Aug 2020 10:52:27 +0800 Subject: [PATCH 02/31] test: fix path mapping --- .mocharc.js | 5 ++++- package.json | 1 + tsconfig.test.json | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.mocharc.js b/.mocharc.js index ceb525497a..f8674754a7 100644 --- a/.mocharc.js +++ b/.mocharc.js @@ -8,5 +8,8 @@ module.exports = { 'packages/plugin-eval/tests/*.spec.ts', 'packages/plugin-teach/tests/*.spec.ts', ], - require: 'ts-node/register/transpile-only', + require: [ + 'ts-node/register/transpile-only', + 'tsconfig-paths/register', + ], } diff --git a/package.json b/package.json index 04007dbaeb..326c4d3656 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "rimraf": "^3.0.2", "semver": "^7.3.2", "ts-node": "^9.0.0", + "tsconfig-paths": "^3.9.0", "typescript": "^4.0.2" } } diff --git a/tsconfig.test.json b/tsconfig.test.json index 9f761ab605..58b195fcd6 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -1,6 +1,7 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { + "baseUrl": ".", "paths": { "koishi-plugin-*": ["packages/plugin-*/src"], "koishi-adapter-*": ["packages/adapter-*/src"], From 5565ff9d4ae9c5bdebb0589cf2dd22df67878fbd Mon Sep 17 00:00:00 2001 From: Shigma <1700011071@pku.edu.cn> Date: Tue, 25 Aug 2020 12:21:30 +0800 Subject: [PATCH 03/31] teach: adjust regexp validator --- packages/plugin-teach/src/database/mysql.ts | 47 +++------------------ packages/plugin-teach/src/internal.ts | 25 +++-------- packages/plugin-teach/tests/basic.spec.ts | 4 +- 3 files changed, 14 insertions(+), 62 deletions(-) diff --git a/packages/plugin-teach/src/database/mysql.ts b/packages/plugin-teach/src/database/mysql.ts index d19f2b888b..c0b3e86b44 100644 --- a/packages/plugin-teach/src/database/mysql.ts +++ b/packages/plugin-teach/src/database/mysql.ts @@ -2,7 +2,6 @@ import { Context, extendDatabase, Message } from 'koishi-core' import { clone, defineProperty, Observed, pick } from 'koishi-utils' import { Dialogue, DialogueTest } from '../utils' import { escape } from 'mysql' -import { RegExpError } from '../internal' import { format } from 'util' import MysqlDatabase from 'koishi-plugin-mysql/dist/database' @@ -12,30 +11,6 @@ declare module 'koishi-core/dist/context' { } } -declare module 'koishi-core/dist/plugins/message' { - namespace Message { - export namespace Teach { - let WhitespaceCharset: string - let NonspaceCharset: string - let UnsupportedCharset: string - let UnsupportedWordBoundary: string - let UnsupportedNongreedy: string - let UnsupportedLookaround: string - let UnsupportedNoncapturing: string - let UnsupportedNamedGroup: string - } - } -} - -Message.Teach.WhitespaceCharset = '问题中的空白字符会被自动删除,你无需使用 \\s。' -Message.Teach.NonspaceCharset = '问题中的空白字符会被自动删除,请使用 . 代替 \\S。' -Message.Teach.UnsupportedCharset = '目前不支持在正则表达式中使用 \\%s,请使用 [%s] 代替。' -Message.Teach.UnsupportedWordBoundary = '目前不支持在正则表达式中使用单词边界。' -Message.Teach.UnsupportedNongreedy = '目前不支持在正则表达式中使用非捕获组。' -Message.Teach.UnsupportedLookaround = '目前不支持在正则表达式中使用断言。' -Message.Teach.UnsupportedNoncapturing = '目前不支持在正则表达式中使用非捕获组。' -Message.Teach.UnsupportedNamedGroup = '目前不支持在正则表达式中使用具名组。' - extendDatabase('koishi-plugin-mysql', { async getDialoguesById(ids, fields) { if (!ids.length) return [] @@ -124,32 +99,22 @@ extendDatabase('koishi-plugin-mysql', ({ listFields }) => export default function apply(ctx: Context, config: Dialogue.Config) { config.validateRegExp = { onEscapeCharacterSet(start, end, kind, negate) { - // eslint-disable-next-line curly - if (kind === 'space') throw negate - ? new RegExpError(Message.Teach.WhitespaceCharset) - : new RegExpError(Message.Teach.NonspaceCharset) - let chars = kind === 'digit' ? '0-9' : '_0-9a-z' - let source = kind === 'digit' ? 'd' : 'w' - if (negate) { - chars = '^' + chars - source = source.toUpperCase() - } - throw new RegExpError(format(Message.Teach.UnsupportedCharset, source, chars)) + throw new SyntaxError('unsupported escape character set') }, onQuantifier(start, end, min, max, greedy) { - if (!greedy) throw new RegExpError(Message.Teach.UnsupportedNongreedy) + if (!greedy) throw new SyntaxError('unsupported non-greedy quantifier') }, onWordBoundaryAssertion() { - throw new RegExpError(Message.Teach.UnsupportedWordBoundary) + throw new SyntaxError('unsupported word boundary assertion') }, onLookaroundAssertionEnter() { - throw new RegExpError(Message.Teach.UnsupportedLookaround) + throw new SyntaxError('unsupported lookaround assertion') }, onGroupEnter() { - throw new RegExpError(Message.Teach.UnsupportedNoncapturing) + throw new SyntaxError('unsupported non-capturing group') }, onCapturingGroupEnter(start, name) { - if (name) throw new RegExpError(Message.Teach.UnsupportedNamedGroup) + if (name) throw new SyntaxError('unsupported named capturing group') }, } diff --git a/packages/plugin-teach/src/internal.ts b/packages/plugin-teach/src/internal.ts index 54ae1a0f6a..f7d5df9682 100644 --- a/packages/plugin-teach/src/internal.ts +++ b/packages/plugin-teach/src/internal.ts @@ -2,9 +2,9 @@ import { Context, Message } from 'koishi-core' import { Dialogue } from './utils' import { update } from './update' import { RegExpValidator } from 'regexpp' -import { defineProperty, Logger } from 'koishi-utils' +import { defineProperty } from 'koishi-utils' import { formatQuestionAnswers } from './search' -import { format, types } from 'util' +import { format } from 'util' import leven from 'leven' declare module 'koishi-core/dist/plugins/message' { @@ -30,14 +30,7 @@ Message.Teach.IllegalRegExp = '问题含有错误的或不支持的正则表达 Message.Teach.MayModifyAnswer = '推测你想修改的是回答而不是问题。发送空行或句号以修改回答,使用 -i 选项以忽略本提示。' Message.Teach.MaybeRegExp = '推测你想%s的问题是正则表达式。发送空行或句号以添加 -x 选项,使用 -i 选项以忽略本提示。' -export class RegExpError extends Error { - name = 'RegExpError' -} - -const validator = new RegExpValidator() - export default function apply(ctx: Context, config: Dialogue.Config) { - const logger = new Logger('teach') defineProperty(ctx.app, 'teachHistory', {}) ctx.command('teach') @@ -86,6 +79,8 @@ export default function apply(ctx: Context, config: Dialogue.Config) { return question.startsWith('^') || question.endsWith('$') } + const validator = new RegExpValidator(config.validateRegExp) + ctx.on('dialogue/before-modify', async (argv) => { const { options, session, target, dialogues } = argv const { question, answer, ignoreHint, regexp } = options @@ -121,17 +116,7 @@ export default function apply(ctx: Context, config: Dialogue.Config) { try { questions.map(q => validator.validatePattern(q)) } catch (error) { - if (!types.isNativeError(error)) { - logger.warn(question, error) - return Message.Teach.IllegalRegExp - } else if (error.name === 'RegExpError') { - return error.message - } else { - if (!error.message.startsWith('SyntaxError')) { - logger.warn(question, error.stack) - } - return Message.Teach.IllegalRegExp - } + return Message.Teach.IllegalRegExp } } }) diff --git a/packages/plugin-teach/tests/basic.spec.ts b/packages/plugin-teach/tests/basic.spec.ts index aad7bf8ae3..2653eba92e 100644 --- a/packages/plugin-teach/tests/basic.spec.ts +++ b/packages/plugin-teach/tests/basic.spec.ts @@ -43,7 +43,9 @@ describe('koishi-plugin-teach', () => { await session1.shouldHaveReply('# foo bar', '问答已存在,编号为 1,如要修改请尝试使用 #1 指令。') await session1.shouldHaveReply('# foo bar -P 1', '修改了已存在的问答,编号为 1。') await session1.shouldHaveReply('#1 -P 1', '问答 1 没有发生改动。') - await session1.shouldHaveReply('#1 ~ baz', '问答 1 已成功修改。') + await session1.shouldHaveReply('#1 baz', '推测你想修改的是回答而不是问题。发送空行或句号以修改回答,使用 -i 选项以忽略本提示。') + await session1.shouldHaveReply('#1 baz', '推测你想修改的是回答而不是问题。发送空行或句号以修改回答,使用 -i 选项以忽略本提示。') + await session1.shouldHaveReply('.', '问答 1 已成功修改。') await session1.shouldHaveReply('foo', 'baz') }) From f630501d14f70eed0169dc746a60e6342da2d651 Mon Sep 17 00:00:00 2001 From: Shigma <1700011071@pku.edu.cn> Date: Tue, 25 Aug 2020 15:01:36 +0800 Subject: [PATCH 04/31] teach: fix history support --- packages/plugin-teach/src/plugins/context.ts | 21 +- .../plugin-teach/src/plugins/successor.ts | 1 + packages/plugin-teach/src/plugins/time.ts | 11 +- packages/plugin-teach/src/plugins/writer.ts | 8 +- packages/plugin-teach/src/update.ts | 4 +- packages/plugin-teach/src/utils.ts | 2 - packages/plugin-teach/tests/basic.spec.ts | 218 +++++++++++++----- 7 files changed, 189 insertions(+), 76 deletions(-) diff --git a/packages/plugin-teach/src/plugins/context.ts b/packages/plugin-teach/src/plugins/context.ts index 2c139eee1a..71fbc0fc90 100644 --- a/packages/plugin-teach/src/plugins/context.ts +++ b/packages/plugin-teach/src/plugins/context.ts @@ -18,12 +18,17 @@ declare module '../utils' { groups?: string[] partial?: boolean reversed?: boolean - noContextOptions?: boolean + } + + interface Config { + useContext?: boolean } } } export default function apply(ctx: Context, config: Dialogue.Config) { + if (config.useContext === false) return + ctx.command('teach') .option('disable', '-d 在当前环境下禁用问答') .option('disableGlobal', '-D 在所有环境下禁用问答', { authority: 3 }) @@ -46,12 +51,12 @@ export default function apply(ctx: Context, config: Dialogue.Config) { } else if (options.disableGlobal && options.enableGlobal) { return '选项 -D, -E 不能同时使用。' } else if (options.disableGlobal && options.disable) { - return '选项 -d, -D 不能同时使用。' + return '选项 -D, -d 不能同时使用。' } else if (options.enable && options.enableGlobal) { - return '选项 -e, -E 不能同时使用。' + return '选项 -E, -e 不能同时使用。' } - argv.noContextOptions = false + let noContextOptions = false if (options.disable) { argv.reversed = true argv.partial = !options.enableGlobal @@ -65,7 +70,7 @@ export default function apply(ctx: Context, config: Dialogue.Config) { argv.partial = false argv.groups = [] } else { - argv.noContextOptions = !options.enable + noContextOptions = !options.enable if (options.target ? options.enable : !options.global) { argv.reversed = false argv.partial = true @@ -74,13 +79,13 @@ export default function apply(ctx: Context, config: Dialogue.Config) { } if ('groups' in options) { - if (argv.noContextOptions) { - return '参数 -g, --groups 必须与 -d/-D/-e/-E 之一同时使用。' + if (noContextOptions) { + return '选项 -g, --groups 必须与 -d/-D/-e/-E 之一同时使用。' } else { argv.groups = options.groups ? options.groups.split(',') : [] } } else if (session.messageType !== 'group' && argv.partial) { - return '非群聊上下文中请使用 -E/-D 进行操作或指定 -g, --groups 参数。' + return '非群聊上下文中请使用 -E/-D 进行操作或指定 -g, --groups 选项。' } }) diff --git a/packages/plugin-teach/src/plugins/successor.ts b/packages/plugin-teach/src/plugins/successor.ts index e2f3afb35f..672b799e4b 100644 --- a/packages/plugin-teach/src/plugins/successor.ts +++ b/packages/plugin-teach/src/plugins/successor.ts @@ -39,6 +39,7 @@ declare module '../utils' { export default function apply(ctx: Context, config: Dialogue.Config) { const { successorTimeout = 20000 } = config + if (!successorTimeout) return ctx.command('teach') .option('setPred', '< 设置前置问题', { type: 'string', validate: RE_DIALOGUES }) diff --git a/packages/plugin-teach/src/plugins/time.ts b/packages/plugin-teach/src/plugins/time.ts index 8bac76ca67..e114e22674 100644 --- a/packages/plugin-teach/src/plugins/time.ts +++ b/packages/plugin-teach/src/plugins/time.ts @@ -1,4 +1,5 @@ import { Context } from 'koishi-core' +import { Dialogue } from '../utils' declare module '../utils' { interface DialogueTest { @@ -10,6 +11,12 @@ declare module '../utils' { startTime: number endTime: number } + + namespace Dialogue { + interface Config { + useTime?: boolean + } + } } export function isHours(value: string) { @@ -19,7 +26,9 @@ export function isHours(value: string) { return !(hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60) } -export default function apply(ctx: Context) { +export default function apply(ctx: Context, config: Dialogue.Config) { + if (config.useTime === false) return + ctx.command('teach') .option('startTime', '-t