From 68bfd61ccf8edce3bd44c2586c3f4cdb546013ed Mon Sep 17 00:00:00 2001 From: gnuxie Date: Mon, 27 Nov 2023 16:00:23 +0000 Subject: [PATCH] Update all of InterfaceManager to use MPS. --- .../interface-manager/DeadDocumentMatrix.ts | 2 +- .../interface-manager/InterfaceCommand.ts | 6 +- .../interface-manager/MatrixHelpRenderer.tsx | 35 +++--- .../MatrixInterfaceAdaptor.ts | 26 ++--- .../interface-manager/MatrixPresentations.tsx | 4 +- .../MatrixPromptForAccept.tsx | 13 +-- .../interface-manager/MatrixPromptUX.ts | 24 ++--- .../MatrixReactionHandler.ts | 6 +- .../interface-manager/ParameterParsing.ts | 102 +++++++++--------- .../interface-manager/PromptForAccept.ts | 8 +- 10 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/commands/interface-manager/DeadDocumentMatrix.ts b/src/commands/interface-manager/DeadDocumentMatrix.ts index 81f1489f..2a38b669 100644 --- a/src/commands/interface-manager/DeadDocumentMatrix.ts +++ b/src/commands/interface-manager/DeadDocumentMatrix.ts @@ -3,7 +3,7 @@ * All rights reserved. */ -import { MatrixSendClient } from "../../MatrixEmitter"; +import { MatrixSendClient } from "matrix-protection-suite-for-matrix-bot-sdk"; import { AbstractNode, DocumentNode, FringeWalker, NodeTag } from "./DeadDocument"; import { HTML_RENDERER } from "./DeadDocumentHtml"; import { MARKDOWN_RENDERER } from "./DeadDocumentMarkdown"; diff --git a/src/commands/interface-manager/InterfaceCommand.ts b/src/commands/interface-manager/InterfaceCommand.ts index 263435ca..40466dcf 100644 --- a/src/commands/interface-manager/InterfaceCommand.ts +++ b/src/commands/interface-manager/InterfaceCommand.ts @@ -29,8 +29,8 @@ limitations under the License. * I'd like to remove the dependency on matrix-bot-sdk. */ +import { ActionResult, isError } from "matrix-protection-suite"; import { ParameterParser, IArgumentStream, IArgumentListParser, ParsedKeywords, ArgumentStream } from "./ParameterParsing"; -import { CommandResult } from "./Validation"; /** * 💀 . o O ( at least I don't have to remember the types ) @@ -38,7 +38,7 @@ import { CommandResult } from "./Validation"; * Probably am "doing something wrong", and no, trying to make this protocol isn't it. */ -export type BaseFunction = (keywords: ParsedKeywords, ...args: any) => Promise>; +export type BaseFunction = (keywords: ParsedKeywords, ...args: any) => Promise>; type CommandLookupEntry = { next?: Map>, @@ -200,7 +200,7 @@ export class InterfaceCommand public async parseThenInvoke(context: ThisParameterType, stream: IArgumentStream): Promise> { const parameterDescription = await this.parseArguments(stream); - if (parameterDescription.isErr()) { + if (isError(parameterDescription)) { // The inner type is irrelevant when it is Err, i don't know how to encode this in TS's type system but whatever. return parameterDescription as ReturnType>; } diff --git a/src/commands/interface-manager/MatrixHelpRenderer.tsx b/src/commands/interface-manager/MatrixHelpRenderer.tsx index 9a91cbc1..882454cc 100644 --- a/src/commands/interface-manager/MatrixHelpRenderer.tsx +++ b/src/commands/interface-manager/MatrixHelpRenderer.tsx @@ -2,16 +2,15 @@ * Copyright (C) 2022 Gnuxie */ -import { MatrixSendClient } from "../../MatrixEmitter"; import { BaseFunction, CommandTable, InterfaceCommand } from "./InterfaceCommand"; import { MatrixContext, MatrixInterfaceAdaptor } from "./MatrixInterfaceAdaptor"; import { ArgumentParseError, ParameterDescription, RestDescription } from "./ParameterParsing"; -import { CommandError, CommandResult } from "./Validation"; import { JSXFactory } from "./JSXFactory"; import { DocumentNode } from "./DeadDocument"; import { renderMatrixAndSend } from "./DeadDocumentMatrix"; -import { CommandException } from "./CommandException"; import { LogService } from "matrix-bot-sdk"; +import { MatrixSendClient } from "matrix-protection-suite-for-matrix-bot-sdk"; +import { ActionException, ActionResult, StringRoomID, isError } from "matrix-protection-suite"; function requiredArgument(argumentName: string): string { return `<${argumentName}>`; @@ -77,45 +76,45 @@ function renderTableHelp(table: CommandTable): DocumentNode { } -export async function renderHelp(client: MatrixSendClient, commandRoomId: string, event: any, result: CommandResult): Promise { - if (result.isErr()) { +export async function renderHelp(client: MatrixSendClient, commandRoomID: StringRoomID, event: any, result: ActionResult): Promise { + if (isError(result)) { throw new TypeError("This command isn't supposed to fail"); } await renderMatrixAndSend( renderTableHelp(result.ok), - commandRoomId, + commandRoomID, event, client ); } -export async function tickCrossRenderer(this: MatrixInterfaceAdaptor, client: MatrixSendClient, commandRoomId: string, event: any, result: CommandResult): Promise { +export async function tickCrossRenderer(this: MatrixInterfaceAdaptor, client: MatrixSendClient, commandRoomID: StringRoomID, event: any, result: ActionResult): Promise { const react = async (emote: string) => { try { - await client.unstableApis.addReactionToEvent(commandRoomId, event['event_id'], emote); + await client.unstableApis.addReactionToEvent(commandRoomID, event['event_id'], emote); } catch (e) { LogService.error("tickCrossRenderer", "Couldn't react to the event", event['event_id'], e); } } - if (result.isOk()) { + if (result.isOkay) { await react('✅') } else { - if (result.err instanceof ArgumentParseError) { + if (result.error instanceof ArgumentParseError) { await renderMatrixAndSend( - renderArgumentParseError(this.interfaceCommand, result.err), - commandRoomId, + renderArgumentParseError(this.interfaceCommand, result.error), + commandRoomID, event, client); - } else if (result.err instanceof CommandException) { - const commandError = result.err; + } else if (result.error instanceof ActionException) { + const commandError = result.error; LogService.error("CommandException", commandError.uuid, commandError.message, commandError.exception); await renderMatrixAndSend( - renderCommandException(this.interfaceCommand, result.err), - commandRoomId, + renderCommandException(this.interfaceCommand, result.error), + commandRoomID, event, client); } else { - await client.replyNotice(commandRoomId, event, result.err.message); + await client.replyNotice(commandRoomID, event, result.error.message); } // reacting is way less important than communicating what happened, do it last. await react('❌'); @@ -146,7 +145,7 @@ function renderArgumentParseError(command: InterfaceCommand, error } -function renderCommandException(command: InterfaceCommand, error: CommandException): DocumentNode { +function renderCommandException(command: InterfaceCommand, error: ActionException): DocumentNode { return There was an unexpected error when processing this command:
{error.message}
diff --git a/src/commands/interface-manager/MatrixInterfaceAdaptor.ts b/src/commands/interface-manager/MatrixInterfaceAdaptor.ts index 02b5fae6..d3b0d132 100644 --- a/src/commands/interface-manager/MatrixInterfaceAdaptor.ts +++ b/src/commands/interface-manager/MatrixInterfaceAdaptor.ts @@ -29,28 +29,28 @@ limitations under the License. * I'd like to remove the dependency on matrix-bot-sdk. */ -import { CommandError, CommandResult } from "./Validation"; import { LogService, MatrixClient } from "matrix-bot-sdk"; import { ReadItem } from "./CommandReader"; -import { MatrixEmitter, MatrixSendClient } from "../../MatrixEmitter"; import { BaseFunction, InterfaceCommand } from "./InterfaceCommand"; import { tickCrossRenderer } from "./MatrixHelpRenderer"; import { CommandInvocationRecord, InterfaceAcceptor, PromptableArgumentStream, PromptOptions } from "./PromptForAccept"; import { ParameterDescription } from "./ParameterParsing"; import { matrixPromptForAccept } from "./MatrixPromptForAccept"; +import { MatrixSendClient, SafeMatrixEmitter } from "matrix-protection-suite-for-matrix-bot-sdk"; +import { ActionError, ActionResult, ResultError, RoomEvent, RoomMessage, StringRoomID, isError } from "matrix-protection-suite"; export interface MatrixContext { client: MatrixSendClient, - emitter: MatrixEmitter, - roomId: string, - event: any, + emitter: SafeMatrixEmitter, + roomID: StringRoomID, + event: RoomMessage, } type RendererSignature = ( this: MatrixInterfaceAdaptor, client: MatrixClient, commandRoomId: string, - event: any, + event: RoomEvent, result: Awaited>) => Promise; export class MatrixInterfaceAdaptor implements InterfaceAcceptor { @@ -58,7 +58,7 @@ export class MatrixInterfaceAdaptor, private readonly renderer: RendererSignature, - private readonly validationErrorHandler?: (client: MatrixClient, roomId: string, event: any, validationError: CommandError) => Promise + private readonly validationErrorHandler?: (client: MatrixClient, roomID: StringRoomID, event: RoomEvent, validationError: ActionError) => Promise ) { } @@ -75,13 +75,13 @@ export class MatrixInterfaceAdaptor>(this.interfaceCommand, executorContext, matrixContext); const stream = new PromptableArgumentStream(args, this, invocationRecord); const executorResult: Awaited> = await this.interfaceCommand.parseThenInvoke(executorContext, stream); - if (executorResult.isErr()) { - this.reportValidationError(matrixContext.client, matrixContext.roomId, matrixContext.event, executorResult.err); + if (isError(executorResult)) { + this.reportValidationError(matrixContext.client, matrixContext.roomID, matrixContext.event, executorResult.error); return; } // just give the renderer the MatrixContext. // we need to give the renderer the command itself! - await this.renderer.apply(this, [matrixContext.client, matrixContext.roomId, matrixContext.event, executorResult]); + await this.renderer.apply(this, [matrixContext.client, matrixContext.roomID, matrixContext.event, executorResult]); } // is this still necessary, surely this should be handled entirely by the renderer? @@ -89,16 +89,16 @@ export class MatrixInterfaceAdaptor { + private async reportValidationError(client: MatrixSendClient, roomID: StringRoomID, event: RoomMessage, validationError: ActionError): Promise { LogService.info("MatrixInterfaceCommand", `User input validation error when parsing command ${JSON.stringify(this.interfaceCommand.designator)}: ${validationError.message}`); if (this.validationErrorHandler) { await this.validationErrorHandler.apply(this, arguments); return; } - await tickCrossRenderer.call(this, client, roomId, event, CommandResult.Err(validationError)); + await tickCrossRenderer.call(this, client, roomID, event, ResultError(validationError)); } - public async promptForAccept(parameter: ParameterDescription, invocationRecord: CommandInvocationRecord): Promise> { + public async promptForAccept(parameter: ParameterDescription, invocationRecord: CommandInvocationRecord): Promise> { if (!(invocationRecord instanceof MatrixInvocationRecord)) { throw new TypeError("The MatrixInterfaceAdaptor only supports invocation records that were produced by itself."); } diff --git a/src/commands/interface-manager/MatrixPresentations.tsx b/src/commands/interface-manager/MatrixPresentations.tsx index 1a3bb109..1fdb1325 100644 --- a/src/commands/interface-manager/MatrixPresentations.tsx +++ b/src/commands/interface-manager/MatrixPresentations.tsx @@ -6,10 +6,10 @@ import { ReadItem } from "./CommandReader"; import { findPresentationType, makePresentationType, simpleTypeValidator } from "./ParameterParsing"; import { UserID } from "matrix-bot-sdk"; -import { MatrixRoomAlias, MatrixRoomID, MatrixRoomReference } from "./MatrixRoomReference"; import { definePresentationRenderer } from "./DeadDocumentPresentation"; import { JSXFactory } from "./JSXFactory"; import { DocumentNode } from "./DeadDocument"; +import { MatrixRoomAlias, MatrixRoomID } from "matrix-protection-suite"; makePresentationType({ @@ -19,7 +19,7 @@ makePresentationType({ makePresentationType({ name: 'MatrixRoomReference', - validator: simpleTypeValidator('MatrixRoomReference', (item: ReadItem) => item instanceof MatrixRoomReference), + validator: simpleTypeValidator('MatrixRoomReference', (item: ReadItem) => item instanceof MatrixRoomID || item instanceof MatrixRoomAlias), }) makePresentationType({ diff --git a/src/commands/interface-manager/MatrixPromptForAccept.tsx b/src/commands/interface-manager/MatrixPromptForAccept.tsx index cbc444ad..5bf889c8 100644 --- a/src/commands/interface-manager/MatrixPromptForAccept.tsx +++ b/src/commands/interface-manager/MatrixPromptForAccept.tsx @@ -3,6 +3,7 @@ * All rights reserved. */ +import { ActionResult, StringUserID } from "matrix-protection-suite"; import { renderMatrixAndSend } from "./DeadDocumentMatrix"; import { BaseFunction, InterfaceCommand } from "./InterfaceCommand"; import { JSXFactory } from "./JSXFactory"; @@ -10,7 +11,6 @@ import { MatrixContext } from "./MatrixInterfaceAdaptor"; import { PromptResponseListener } from "./MatrixPromptUX"; import { ParameterDescription } from "./ParameterParsing"; import { PromptOptions } from "./PromptForAccept"; -import { CommandResult } from "./Validation"; async function promptDefault(this: MatrixContext, parameter: ParameterDescription, command: InterfaceCommand, defaultPrompt: PresentationType) { await renderMatrixAndSend( @@ -18,7 +18,7 @@ async function promptDefault(this: MatrixContext, parameter: P No argument was provided for the parameter {parameter.name}, would you like to accept the default?
{defaultPrompt}
, - this.roomId, this.event, this.client + this.roomID, this.event, this.client ) } @@ -38,22 +38,23 @@ async function promptSuggestions( })} , - this.roomId, this.event, this.client + this.roomID, this.event, this.client )).at(0) as string; } export async function matrixPromptForAccept ( this: MatrixContext, parameter: ParameterDescription, command: InterfaceCommand, promptOptions: PromptOptions -): Promise> { - const promptHelper = new PromptResponseListener(this.emitter, await this.client.getUserId(), this.client); +): Promise> { + // FIXME: is there a better way to get the clinet ID? why isn't Draupnir in the command context? + const promptHelper = new PromptResponseListener(this.emitter, await this.client.getUserId() as StringUserID, this.client); if (promptOptions.default) { await promptDefault.call(this, parameter, command, promptOptions.default); throw new TypeError("default prompts are not implemented yet."); } return await promptHelper.waitForPresentationList( promptOptions.suggestions, - this.roomId, + this.roomID, promptSuggestions.call(this, parameter, command, promptOptions.suggestions) ); } diff --git a/src/commands/interface-manager/MatrixPromptUX.ts b/src/commands/interface-manager/MatrixPromptUX.ts index 8886932d..13434f7b 100644 --- a/src/commands/interface-manager/MatrixPromptUX.ts +++ b/src/commands/interface-manager/MatrixPromptUX.ts @@ -3,9 +3,9 @@ * All rights reserved. */ -import { MatrixEmitter, MatrixSendClient } from "../../MatrixEmitter"; -import { CommandError, CommandResult } from "./Validation"; import { LogService } from "matrix-bot-sdk"; +import { ActionError, ActionResult, Ok, StringUserID } from "matrix-protection-suite"; +import { MatrixSendClient, SafeMatrixEmitter } from "matrix-protection-suite-for-matrix-bot-sdk"; type PresentationByReactionKey = Map; @@ -29,8 +29,8 @@ class ReactionHandler { private readonly promptRecordByEvent: Map> = new Map(); constructor( - matrixEmitter: MatrixEmitter, - private readonly userId: string, + matrixEmitter: SafeMatrixEmitter, + private readonly userID: StringUserID, private readonly client: MatrixSendClient, ) { matrixEmitter.on('room.event', this.handleEvent.bind(this)) @@ -83,7 +83,7 @@ class ReactionHandler { if (!(typeof relatedEventId === 'string' && typeof reactionKey === 'string')) { return; } - if (event['sender'] === this.userId) { + if (event['sender'] === this.userID) { return; } const entry = this.promptRecordByEvent.get(relatedEventId); @@ -104,7 +104,7 @@ class ReactionHandler { public async waitForReactionToPrompt( roomId: string, eventId: string, presentationByReaction: PresentationByReactionKey, timeout = 600_000 // ten minutes - ): Promise> { + ): Promise> { let record; let timeoutId; const presentationOrTimeout = await Promise.race([ @@ -120,9 +120,9 @@ class ReactionHandler { if (record !== undefined) { this.removePromptRecordForEvent(eventId, record); } - return CommandError.Result(`Timed out while waiting for a response to the prompt`); + return ActionError.Result(`Timed out while waiting for a response to the prompt`); } else { - return CommandResult.Ok(presentationOrTimeout as T); + return Ok(presentationOrTimeout as T); } } } @@ -154,11 +154,11 @@ export class PromptResponseListener { private readonly reactionHandler: ReactionHandler; constructor( - matrixEmitter: MatrixEmitter, - userId: string, + matrixEmitter: SafeMatrixEmitter, + userID: StringUserID, client: MatrixSendClient, ) { - this.reactionHandler = new ReactionHandler(matrixEmitter, userId, client); + this.reactionHandler = new ReactionHandler(matrixEmitter, userID, client); } private indexToReactionKey(index: number): string { @@ -168,7 +168,7 @@ export class PromptResponseListener { // This won't work, we have to have a special key in the original event // that means we should be waiting for it, that can't be abused/forged. // As we can't have the event id AOT. - public async waitForPresentationList(presentations: T[], roomId: string, eventPromise: Promise): Promise> { + public async waitForPresentationList(presentations: T[], roomId: string, eventPromise: Promise): Promise> { const presentationByReactionKey = presentations.reduce( (map: PresentationByReactionKey, presentation: T, index: number) => { return map.set(this.indexToReactionKey(index), presentation); diff --git a/src/commands/interface-manager/MatrixReactionHandler.ts b/src/commands/interface-manager/MatrixReactionHandler.ts index d6ad9ae8..f4739bd4 100644 --- a/src/commands/interface-manager/MatrixReactionHandler.ts +++ b/src/commands/interface-manager/MatrixReactionHandler.ts @@ -4,8 +4,8 @@ */ import { EventEmitter } from "stream"; -import { MatrixEmitter, MatrixSendClient } from "../../MatrixEmitter"; import { LogService } from "matrix-bot-sdk"; +import { MatrixSendClient, SafeMatrixEmitter } from "matrix-protection-suite-for-matrix-bot-sdk"; const REACTION_ANNOTATION_KEY = 'ge.applied-langua.ge.draupnir.reaction_handler'; @@ -92,14 +92,14 @@ export class MatrixReactionHandler extends EventEmitter { * Start listening for reactions to events. * Called normally by an associated mjolnir instance when it is started. */ - public start(emitter: MatrixEmitter): void { + public start(emitter: SafeMatrixEmitter): void { emitter.on('room.event', this.listener); } /** * Stop listening for reactions to events. */ - public stop(emitter: MatrixEmitter): void { + public stop(emitter: SafeMatrixEmitter): void { emitter.off('room.event', this.listener); } diff --git a/src/commands/interface-manager/ParameterParsing.ts b/src/commands/interface-manager/ParameterParsing.ts index fa7c3250..5ec5258b 100644 --- a/src/commands/interface-manager/ParameterParsing.ts +++ b/src/commands/interface-manager/ParameterParsing.ts @@ -24,15 +24,15 @@ limitations under the License. * are NOT distributed, contributed, or committed under the Apache License. */ +import { ActionError, ActionResult, Ok, ResultError, isError } from "matrix-protection-suite"; import { ISuperCoolStream, Keyword, ReadItem, SuperCoolStream } from "./CommandReader"; import { PromptOptions } from "./PromptForAccept"; -import { CommandError, CommandResult } from "./Validation"; export interface IArgumentStream extends ISuperCoolStream { rest(): ReadItem[], isPromptable(): boolean, // should prompt really return a new stream? - prompt(parameterDescription: ParameterDescription): Promise>, + prompt(parameterDescription: ParameterDescription): Promise>, } export class ArgumentStream extends SuperCoolStream implements IArgumentStream { @@ -44,7 +44,7 @@ export class ArgumentStream extends SuperCoolStream implements IArgu return false; } - prompt(parameterDescription: ParameterDescription): Promise> { + prompt(parameterDescription: ParameterDescription): Promise> { throw new TypeError("This argument stream is NOT promptable, did you even check isPromptable()."); } } @@ -52,7 +52,7 @@ export class ArgumentStream extends SuperCoolStream implements IArgu // TODO: Presentation types should be extracted to their own file. // FIXME: PresentationTypes should not be limited to ReadItems. -export type PredicateIsParameter = (readItem: ReadItem) => CommandResult; +export type PredicateIsParameter = (readItem: ReadItem) => ActionResult; export interface PresentationType { validator: PredicateIsParameter, @@ -86,10 +86,10 @@ export function simpleTypeValidator(name: string, predicate: (readItem: ReadItem return (readItem: ReadItem) => { const result = predicate(readItem); if (result) { - return CommandResult.Ok(result); + return Ok(result); } else { // How do we accurately denote the type when it includes spaces in its name, same for the read item? - return CommandError.Result(`Was expecting a match for the presentation type: ${name} but got ${readItem}.`); + return ActionError.Result(`Was expecting a match for the presentation type: ${name} but got ${readItem}.`); } } } @@ -98,7 +98,7 @@ export function presentationTypeOf(presentation: unknown): PresentationType|unde // We have no concept of presentation-subtype // But we have a top type which is any... const candidates = [...PRESENTATION_TYPES.values()] - .filter(possibleType => possibleType.validator(presentation as ReadItem).isOk() + .filter(possibleType => possibleType.validator(presentation as ReadItem).isOkay && possibleType.name !== 'any' ); if (candidates.length === 0) { @@ -154,34 +154,34 @@ export class RestDescription implements ParameterDesc * Parse the rest of a command. * @param stream An argument stream that starts at the rest of a command. * @param keywordParser Used to store any keywords found in the rest of the command. - * @returns A CommandResult of ReadItems associated with the rest of the command. + * @returns A ActionResult of ReadItems associated with the rest of the command. * If a ReadItem or Keyword is invalid for the command, then an error will be returned. */ - public async parseRest(stream: IArgumentStream, promptForRest: boolean, keywordParser: KeywordParser): Promise> { + public async parseRest(stream: IArgumentStream, promptForRest: boolean, keywordParser: KeywordParser): Promise> { const items: ReadItem[] = []; if (this.prompt && promptForRest && stream.isPromptable() && stream.peekItem() === undefined) { const result = await stream.prompt(this); - if (result.isErr()) { - return result as any; + if (isError(result)) { + return result; } } while (stream.peekItem() !== undefined) { const keywordResult = keywordParser.parseKeywords(stream); - if (keywordResult.isErr()) { - return CommandResult.Err(keywordResult.err); + if (isError(keywordResult)) { + return keywordResult; } if (stream.peekItem() !== undefined) { const validationResult = this.acceptor.validator(stream.peekItem()); - if (validationResult.isErr()) { + if (isError(validationResult)) { return ArgumentParseError.Result( - validationResult.err.message, + validationResult.error.message, { parameter: this, stream } ); } items.push(stream.readItem()); } } - return CommandResult.Ok(items); + return Ok(items); } } @@ -263,24 +263,24 @@ class KeywordParser { } - private readKeywordAssociatedProperty(keyword: KeywordPropertyDescription, itemStream: IArgumentStream): CommandResult { + private readKeywordAssociatedProperty(keyword: KeywordPropertyDescription, itemStream: IArgumentStream): ActionResult { if (itemStream.peekItem() !== undefined && !(itemStream.peekItem() instanceof Keyword)) { const validationResult = keyword.acceptor.validator(itemStream.peekItem()); - if (validationResult.isOk()) { - return CommandResult.Ok(itemStream.readItem()); + if (validationResult.isOkay) { + return Ok(itemStream.readItem()); } else { - return ArgumentParseError.Result(validationResult.err.message, { parameter: keyword, stream: itemStream }); + return ArgumentParseError.Result(validationResult.error.message, { parameter: keyword, stream: itemStream }); } } else { if (!keyword.isFlag) { return ArgumentParseError.Result(`An associated argument was not provided for the keyword ${keyword.name}.`, { parameter: keyword, stream: itemStream }); } else { - return CommandResult.Ok(true); + return Ok(true); } } } - public parseKeywords(itemStream: IArgumentStream): CommandResult { + public parseKeywords(itemStream: IArgumentStream): ActionResult { while (itemStream.peekItem() !== undefined && itemStream.peekItem() instanceof Keyword) { const item = itemStream.readItem() as Keyword; const description = this.description.description[item.designator]; @@ -298,7 +298,7 @@ class KeywordParser { } } else { const associatedPropertyResult = this.readKeywordAssociatedProperty(description, itemStream); - if (associatedPropertyResult.isErr()) { + if (isError(associatedPropertyResult)) { return associatedPropertyResult; } else { this.arguments.set(description.name, associatedPropertyResult.ok); @@ -306,21 +306,21 @@ class KeywordParser { } } - return CommandResult.Ok(this); + return Ok(this); } - public async parseRest(stream: IArgumentStream, shouldPromptForRest = false, restDescription?: RestDescription): Promise> { + public async parseRest(stream: IArgumentStream, shouldPromptForRest = false, restDescription?: RestDescription): Promise> { if (restDescription !== undefined) { return await restDescription.parseRest(stream, shouldPromptForRest, this) } else { const result = this.parseKeywords(stream); - if (result.isErr()) { - return CommandResult.Err(result.err); + if (isError(result)) { + return result; } if (stream.peekItem() !== undefined) { - return CommandError.Result(`There is an unexpected non-keyword argument ${JSON.stringify(stream.peekItem())}`); + return ActionError.Result(`There is an unexpected non-keyword argument ${JSON.stringify(stream.peekItem())}`); } else { - return CommandResult.Ok(undefined); + return Ok(undefined); } } } @@ -347,11 +347,11 @@ export interface ParameterDescription { prompt?: Prompt, } -export type ParameterParser = (stream: IArgumentStream) => Promise>; +export type ParameterParser = (stream: IArgumentStream) => Promise>; // So this should really just be something used by defineInterfaceCommand which turns parameters into a validator that can be used. // It can't be, because then otherwise how does the semantics for union work? -// We should have a new type of CommandResult that accepts a ParamterDescription, and can render what's wrong (e.g. missing parameter). +// We should have a new type of ActionResult that accepts a ParamterDescription, and can render what's wrong (e.g. missing parameter). // Showing where in the item stream it is missing and the command syntax and everything lovely like that. // How does that work with Union? export function parameters(descriptions: ParameterDescription[], rest: undefined|RestDescription = undefined, keywords: KeywordsDescription = new KeywordsDescription({}, false)): IArgumentListParser { @@ -377,21 +377,21 @@ class ArgumentListParser implements IArgumentListParser { ) { } - public async parse(stream: IArgumentStream): Promise> { + public async parse(stream: IArgumentStream): Promise> { let hasPrompted = false; const keywordsParser = this.keywords.getParser(); for (const parameter of this.descriptions) { // it eats any keywords at any point in the stream // as they can appear at any point technically. const keywordResult = keywordsParser.parseKeywords(stream); - if (keywordResult.isErr()) { - return CommandResult.Err(keywordResult.err); + if (isError(keywordResult)) { + return keywordResult; } if (stream.peekItem() === undefined) { if (parameter.prompt && stream.isPromptable()) { const promptResult = await stream.prompt(parameter); - if (promptResult.isErr()) { - return promptResult as any; + if (isError(promptResult)) { + return promptResult; } hasPrompted = true; } else { @@ -402,20 +402,20 @@ class ArgumentListParser implements IArgumentListParser { } } const result = parameter.acceptor.validator(stream.peekItem()); - if (result.isErr()) { - return ArgumentParseError.Result(result.err.message, { parameter, stream }); + if (isError(result)) { + return ArgumentParseError.Result(result.error.message, { parameter, stream }); } stream.readItem(); } const restResult = await keywordsParser.parseRest(stream, hasPrompted, this.rest); - if (restResult.isErr()) { - return CommandResult.Err(restResult.err); + if (isError(restResult)) { + return restResult; } const immediateArguments = restResult.ok === undefined || restResult.ok.length === 0 ? stream.source : stream.source.slice(0, stream.source.indexOf(restResult.ok[0])) - return CommandResult.Ok({ + return Ok({ immediateArguments: immediateArguments, keywords: keywordsParser.getKeywords(), rest: restResult.ok @@ -423,15 +423,15 @@ class ArgumentListParser implements IArgumentListParser { } } -export class AbstractArgumentParseError extends CommandError { +export class AbstractArgumentParseError extends ActionError { constructor( public readonly stream: IArgumentStream, message: string) { super(message) } - public static Result(message: string, options: { stream: IArgumentStream }): CommandResult { - return CommandResult.Err(new AbstractArgumentParseError(options.stream, message)); + public static Result(message: string, options: { stream: IArgumentStream }): ActionResult { + return ResultError(new AbstractArgumentParseError(options.stream, message)); } } @@ -443,14 +443,14 @@ export class ArgumentParseError extends AbstractArgumentParseError { super(stream, message) } - public static Result(message: string, options: { parameter: ParameterDescription, stream: IArgumentStream }): CommandResult { - return CommandResult.Err(new ArgumentParseError(options.parameter, options.stream, message)); + public static Result(message: string, options: { parameter: ParameterDescription, stream: IArgumentStream }): ActionResult { + return ResultError(new ArgumentParseError(options.parameter, options.stream, message)); } } export class UnexpectedArgumentError extends AbstractArgumentParseError { - public static Result(message: string, options: { stream: IArgumentStream }): CommandResult { - return CommandResult.Err(new UnexpectedArgumentError(options.stream, message)); + public static Result(message: string, options: { stream: IArgumentStream }): ActionResult { + return ResultError(new UnexpectedArgumentError(options.stream, message)); } } @@ -464,10 +464,10 @@ export function union(...presentationTypes: PresentationType[]): PresentationTyp return { name, validator: (readItem: ReadItem) => { - if (presentationTypes.some(p => p.validator(readItem).isOk())) { - return CommandResult.Ok(true); + if (presentationTypes.some(p => p.validator(readItem).isOkay)) { + return Ok(true); } else { - return CommandError.Result(`Read item didn't match any of the presentaiton types ${name}`); + return ActionError.Result(`Read item didn't match any of the presentaiton types ${name}`); } } } diff --git a/src/commands/interface-manager/PromptForAccept.ts b/src/commands/interface-manager/PromptForAccept.ts index c87e0374..6fafbca9 100644 --- a/src/commands/interface-manager/PromptForAccept.ts +++ b/src/commands/interface-manager/PromptForAccept.ts @@ -3,10 +3,10 @@ * All rights reserved. */ +import { ActionResult } from "matrix-protection-suite"; import { ReadItem } from "./CommandReader"; import { BaseFunction, InterfaceCommand } from "./InterfaceCommand"; import { ArgumentStream, ParameterDescription } from "./ParameterParsing"; -import { CommandResult } from "./Validation"; export interface PromptOptions { readonly suggestions: PresentationType[] @@ -19,7 +19,7 @@ export interface PromptOptions { */ export interface InterfaceAcceptor { readonly isPromptable: boolean - promptForAccept(parameter: ParameterDescription, invocationRecord: CommandInvocationRecord): Promise> + promptForAccept(parameter: ParameterDescription, invocationRecord: CommandInvocationRecord): Promise> } export interface CommandInvocationRecord { @@ -43,12 +43,12 @@ export class PromptableArgumentStream extends ArgumentStream { return this.interfaceAcceptor.isPromptable } - public async prompt(parameterDescription: ParameterDescription): Promise> { + public async prompt(parameterDescription: ParameterDescription): Promise> { const result = await this.interfaceAcceptor.promptForAccept( parameterDescription, this.invocationRecord ); - if (result.isOk()) { + if (result.isOkay) { this.source.push(result.ok); } return result;