diff --git a/package.json b/package.json index d4bdf279..ea03e12a 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "make-dir-cli": "^3.0.0", "prettier": "^2.7.1", "ts-node": "^10.9.1", - "typescript": "^4.8.4", + "typescript": "^4.9.3", "vitest": "^0.25.2" } } diff --git a/src/adaptor/proxy/command/schema.ts b/src/adaptor/proxy/command/schema.ts index a27aed02..e0e22374 100644 --- a/src/adaptor/proxy/command/schema.ts +++ b/src/adaptor/proxy/command/schema.ts @@ -1,13 +1,13 @@ import { - Param, + Params, ParamsValues, ParseError, ParsedSchema, ParsedSubCommand, Schema, SubCommand, - SubCommandEntries, SubCommandGroup, + SubCommands, makeError } from '../../../model/command-schema.js'; @@ -18,12 +18,12 @@ const hasOwn = >( key: PropertyKey ): key is keyof O => Object.hasOwn(object, key); -const parseParams =

( +const parseParams = ( args: string[], - schema: Schema, P> | SubCommand

-): ['Ok', ParamsValues

] | ['Err', ParseError] => { + schema: S +): ['Ok', ParamsValues>] | ['Err', ParseError] => { if (!schema.params) { - return ['Ok', [] as ParamsValues

]; + return ['Ok', [] as ParamsValues>]; } const values: unknown[] = []; for (const param of schema.params) { @@ -108,13 +108,17 @@ const parseParams =

( break; } } - return ['Ok', values as ParamsValues

]; + return ['Ok', values as ParamsValues>]; }; -const parseSubCommand = ( +const isSubCommandGroup = (subCommand: { + type?: string; +}): subCommand is SubCommandGroup => subCommand.type === 'SUB_COMMAND_GROUP'; + +const parseSubCommand = ( args: string[], - schema: Schema | SubCommandGroup -): ['Ok', ParsedSubCommand] | ['Err', ParseError] => { + schema: S +): ['Ok', ParsedSubCommand>] | ['Err', ParseError] => { const subCommandNames = Object.getOwnPropertyNames(schema.subCommands); const arg = args.shift(); @@ -126,9 +130,9 @@ const parseSubCommand = ( if (!hasOwn(schema.subCommands, arg)) { return ['Err', ['UNKNOWN_COMMAND', Object.keys(schema.subCommands), arg]]; } - const subCommandKey: keyof E = arg; + const subCommandKey: keyof SubCommands = arg; - const subCommand = schema.subCommands[subCommandKey]; + const subCommand = (schema.subCommands as SubCommands)[subCommandKey]; if ( !( typeof subCommand === 'object' && @@ -138,11 +142,8 @@ const parseSubCommand = ( ) { return ['Err', ['OTHERS', 'unreachable']]; } - if (subCommand['type'] === 'SUB_COMMAND_GROUP') { - const subSubCommand = parseSubCommand( - args, - subCommand as SubCommandGroup - ); + if (isSubCommandGroup(subCommand)) { + const subSubCommand = parseSubCommand(args, subCommand); if (subSubCommand[0] === 'Err') { return subSubCommand; } @@ -152,7 +153,7 @@ const parseSubCommand = ( name: subCommandKey, type: 'SUB_COMMAND', subCommand: subSubCommand[1] - } as unknown as ParsedSubCommand + } as unknown as ParsedSubCommand> ]; } const params = parseParams(args, subCommand); @@ -165,17 +166,13 @@ const parseSubCommand = ( name: subCommandKey, type: 'PARAMS', params: params[1] - } as ParsedSubCommand + } as unknown as ParsedSubCommand> ]; } return ['Err', ['UNKNOWN_COMMAND', Object.keys(schema.subCommands), arg]]; }; -export const parseStrings = < - E, - P extends readonly Param[], - S extends Schema ->( +export const parseStrings = ( args: string[], schema: S ): ['Ok', ParsedSchema] | ['Err', ParseError] => { @@ -225,11 +222,7 @@ export const parseStrings = < return subCommandRes; }; -export const parseStringsOrThrow = < - E, - P extends readonly Param[], - S extends Schema ->( +export const parseStringsOrThrow = ( args: string[], schema: S ): ParsedSchema => { diff --git a/src/model/command-schema.ts b/src/model/command-schema.ts index fc626b33..2a2eb342 100644 --- a/src/model/command-schema.ts +++ b/src/model/command-schema.ts @@ -128,14 +128,12 @@ export type ParamsValues = Equal extends true * @export * @interface SubCommand */ -export interface SubCommand

{ +export interface SubCommand { type: 'SUB_COMMAND'; - params?: P; + params?: readonly Param[]; } -export const isValidSubCommand =

( - sc: SubCommand

-): boolean => { +export const isValidSubCommand = (sc: SubCommand): boolean => { if (!sc.params) { return true; } @@ -156,19 +154,14 @@ export const isValidSubCommand =

( return lastRequiredParam < firstOptionalParam; }; -export const assertValidSubCommand =

( - sc: SubCommand

-): void => { +export const assertValidSubCommand = (sc: SubCommand): void => { if (!isValidSubCommand(sc)) { console.dir(sc); throw new Error('assertion failure'); } }; -export type SubCommandEntries = Record< - string, - SubCommand | SubCommandGroup> ->; +export type SubCommandEntries = Record; /** * サブコマンドが属するグループ。これ単体ではコマンドとして実行できない。 @@ -176,9 +169,9 @@ export type SubCommandEntries = Record< * @export * @interface SubCommandGroup */ -export interface SubCommandGroup { +export interface SubCommandGroup { type: 'SUB_COMMAND_GROUP'; - subCommands: Readonly; + subCommands: SubCommandEntries; } /** @@ -189,10 +182,10 @@ export interface SubCommandGroup { * @export * @interface Schema */ -export interface Schema, P = readonly Param[]> { +export interface Schema { names: readonly string[]; - subCommands: Readonly; - params?: P; + subCommands: SubCommandEntries; + params?: readonly Param[]; } /** @@ -215,23 +208,19 @@ export type ParsedSchema = { * @typedef ParsedParameter * @template S コマンドスキーマの型 */ -export type ParsedParameter = S extends SubCommand +export type ParsedParameter = S extends SubCommand ? { type: 'PARAMS'; - params: ParamsValues

; + params: ParamsValues>; + } + : S extends SubCommandGroup + ? { + type: 'SUB_COMMAND'; + subCommand: ParsedSubCommand>; } - : S extends SubCommandGroup - ? R extends SubCommandEntries - ? { - type: 'SUB_COMMAND'; - subCommand: ParsedSubCommand; - } - : never : never; -export type HasSubCommand = - | Schema> - | SubCommandGroup>; +export type HasSubCommand = Schema | SubCommandGroup; /** * コマンドのスキーマ `S` のサブコマンドのみに対応するパース結果の型を返す。 @@ -246,10 +235,12 @@ export type ParsedSubCommand = { } & ParsedParameter; }[keyof E]; -export type SubCommands = S extends Schema - ? C - : S extends SubCommandGroup - ? C +export type Params = S extends { params: readonly Param[] } + ? S['params'] + : never; + +export type SubCommands = S extends { subCommands: SubCommandEntries } + ? S['subCommands'] : never; /** diff --git a/src/service/command.ts b/src/service/command.ts index 23e52c8f..5f1d83ec 100644 --- a/src/service/command.ts +++ b/src/service/command.ts @@ -17,7 +17,6 @@ import { } from './command/kaere.js'; import { KokuseiChousa, MemberStats } from './command/kokusei-chousa.js'; import { MembersWithRoleRepository, RoleRank } from './command/role-rank.js'; -import type { Param, Schema } from '../model/command-schema.js'; import { Ping, PingCommand } from './command/ping.js'; import { RoleCreate, RoleCreateManager } from './command/role-create.js'; import { RoleInfo, RoleStatsRepository } from './command/role-info.js'; @@ -29,6 +28,7 @@ import type { CommandResponder } from './command/command-message.js'; import type { CommandRunner } from '../runner/command.js'; import { HelpCommand } from './command/help.js'; import { Meme } from './command/meme.js'; +import type { Schema } from '../model/command-schema.js'; import type { VoiceConnectionFactory } from './voice-connection.js'; export const registerAllCommandResponder = ({ @@ -99,9 +99,7 @@ export const registerAllCommandResponder = ({ ]; for (const responder of allResponders) { commandRunner.addResponder( - responder as unknown as CommandResponder< - Schema, readonly Param[]> - > + responder as unknown as CommandResponder ); } }; diff --git a/src/service/command/command-message.ts b/src/service/command/command-message.ts index 25d05992..0c9910d0 100644 --- a/src/service/command/command-message.ts +++ b/src/service/command/command-message.ts @@ -10,7 +10,7 @@ import type { Snowflake } from '../../model/id.js'; * @interface CommandMessage * @template S スキーマの型 */ -export interface CommandMessage>> { +export interface CommandMessage { /** * コマンドの送信者の ID。 * @@ -96,13 +96,13 @@ export interface HelpInfo { description: string; } -export interface CommandResponder>> { +export interface CommandResponder { help: Readonly; schema: Readonly; on(message: CommandMessage): Promise; } -export const createMockMessage = >>( +export const createMockMessage = ( args: Readonly>, reply?: (message: EmbedMessage) => void | Promise, partial?: Readonly, 'reply'>>> diff --git a/src/service/command/help.ts b/src/service/command/help.ts index d21206df..735d573e 100644 --- a/src/service/command/help.ts +++ b/src/service/command/help.ts @@ -3,10 +3,10 @@ import type { CommandResponder, HelpInfo } from './command-message.js'; -import type { Param, Schema } from '../../model/command-schema.js'; import type { CommandRunner } from '../../runner/command.js'; import type { EmbedPage } from '../../model/embed-message.js'; +import type { Schema } from '../../model/command-schema.js'; const SCHEMA = { names: ['help', 'h'], @@ -37,9 +37,7 @@ export class HelpCommand implements CommandResponder { description, names, params - }: Readonly< - HelpInfo & Schema, readonly Param[]> - >): EmbedPage { + }: Readonly): EmbedPage { const patternsWithDesc: [string, string][] = params?.map(({ name, description, defaultValue }) => [ defaultValue === undefined diff --git a/yarn.lock b/yarn.lock index be748566..df7a0418 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3007,10 +3007,10 @@ type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== -typescript@^4.8.4: - version "4.8.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== +typescript@^4.9.3: + version "4.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" + integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== uglify-js@^3.1.4: version "3.16.3"