diff --git a/.eslintrc.js b/.eslintrc.js index 04e9655d..92e65f3e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -31,6 +31,7 @@ module.exports = { 'no-multiple-empty-lines': 'error', 'lines-between-class-members': 'off', '@typescript-eslint/lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true, exceptAfterOverload: true }], + '@typescript-eslint/no-empty-function': 'off', }, settings: { 'import/parsers': { diff --git a/src/client/query/providers.ts b/src/client/query/providers.ts index ad938483..af84c800 100644 --- a/src/client/query/providers.ts +++ b/src/client/query/providers.ts @@ -4,7 +4,6 @@ import { ProfileDocumentNode, } from '@superfaceai/ast'; -import { UnexpectedError } from '../../internal/errors'; import { MapInterpreter, ProfileParameterValidator, @@ -14,9 +13,7 @@ import { err, ok, Result } from '../../lib'; import { Config } from '../config'; import { fetchMapAST } from './registry'; -function forceCast(_: unknown): _ is T { - return true; -} +function forceCast(_: unknown): asserts _ is T {} export class BoundProvider { private profileValidator: ProfileParameterValidator; @@ -25,8 +22,7 @@ export class BoundProvider { private profileAST: ProfileDocumentNode, private mapAST: MapDocumentNode, private config: Config, - // private usecase: string, - private baseUrl?: string // private validationFunction: (input: unknown) => input is TResult = isUnknown + private baseUrl?: string ) { this.profileValidator = new ProfileParameterValidator(this.profileAST); } @@ -34,10 +30,10 @@ export class BoundProvider { /** Performs the usecase */ - async perform( - input: TInput, - usecase: string - ): Promise> { + async perform< + TInput extends NonPrimitive | undefined = undefined, + TResult = unknown + >(usecase: string, input?: TInput): Promise> { const inputValidation = this.profileValidator.validate( input, 'input', @@ -71,15 +67,9 @@ export class BoundProvider { return err(resultValidation.error); } - if (forceCast(result.value)) { - return ok(result.value); - } + forceCast(result.value); - return err( - new UnexpectedError( - 'This should be unreachable; how did you reach it? Are you magic?' - ) - ); + return ok(result.value); } public get serviceId(): string | undefined { diff --git a/src/internal/errors.ts b/src/internal/errors.ts index c72ef154..8d43d9db 100644 --- a/src/internal/errors.ts +++ b/src/internal/errors.ts @@ -3,7 +3,7 @@ export class ErrorBase { } export class UnexpectedError extends ErrorBase { - constructor(public message: string) { + constructor(public message: string, public additionalContext?: unknown) { super('UnexpectedError', message); } } diff --git a/src/internal/interpreter/map-interpreter.ts b/src/internal/interpreter/map-interpreter.ts index 4466e5ed..b06fb366 100644 --- a/src/internal/interpreter/map-interpreter.ts +++ b/src/internal/interpreter/map-interpreter.ts @@ -55,7 +55,9 @@ function assertUnreachable(node: MapASTNode): never { throw new UnexpectedError(`Invalid Node kind: ${node.kind}`); } -export interface MapParameters { +export interface MapParameters< + TInput extends NonPrimitive | undefined = undefined +> { usecase?: string; auth?: Config['auth']; baseUrl?: string; @@ -93,7 +95,8 @@ interface Stack { error?: MapInterpreterError; } -export class MapInterpreter implements MapVisitor { +export class MapInterpreter + implements MapVisitor { private operations: Record = {}; private stack: Stack[] = []; private ast?: MapDocumentNode; diff --git a/src/internal/interpreter/profile-parameter-validator.errors.ts b/src/internal/interpreter/profile-parameter-validator.errors.ts index b791fc85..d516f1e9 100644 --- a/src/internal/interpreter/profile-parameter-validator.errors.ts +++ b/src/internal/interpreter/profile-parameter-validator.errors.ts @@ -76,6 +76,9 @@ export function formatErrors(errors?: ValidationError[]): string { case 'enumValue': return `${prefix}Invalid enum value`; + case 'wrongInput': + return `Wrong input`; + default: throw new Error('Invalid error!'); } diff --git a/src/internal/interpreter/profile-parameter-validator.ts b/src/internal/interpreter/profile-parameter-validator.ts index 86c89c28..770544bd 100644 --- a/src/internal/interpreter/profile-parameter-validator.ts +++ b/src/internal/interpreter/profile-parameter-validator.ts @@ -19,6 +19,7 @@ import { import createDebug from 'debug'; import { err, ok, Result } from '../../lib'; +import { UnexpectedError } from '../errors'; import { ProfileVisitor } from './interfaces'; import { addFieldToErrors, @@ -96,17 +97,21 @@ export class ProfileParameterValidator implements ProfileVisitor { kind: ProfileParameterKind, usecase: string ): Result { - const validator = this.visit(this.ast, kind, usecase); - const [result, errors] = validator(input); + try { + const validator = this.visit(this.ast, kind, usecase); + const [result, errors] = validator(input); - if (result !== true) { - const error = - kind === 'input' ? InputValidationError : ResultValidationError; + if (result !== true) { + const error = + kind === 'input' ? InputValidationError : ResultValidationError; - return err(new error(errors)); - } + return err(new error(errors)); + } - return ok(undefined); + return ok(undefined); + } catch (e) { + return err(new UnexpectedError('Unknown error from validator', e)); + } } visit( @@ -515,7 +520,7 @@ export class ProfileParameterValidator implements ProfileVisitor { return (input: unknown): ValidationResult => { if ( - typeof input === undefined || + typeof input === 'undefined' || (typeof input === 'object' && (input === null || Object.keys(input).length === 0)) ) {