Skip to content

Commit

Permalink
Merge pull request #23 from superfaceai/feature/provider-dx
Browse files Browse the repository at this point in the history
chore: Improve Provider DX
  • Loading branch information
TheEdward162 authored Dec 17, 2020
2 parents 08e5a10 + 84b38ee commit c0988c2
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 30 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -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': {
Expand Down
26 changes: 8 additions & 18 deletions src/client/query/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
ProfileDocumentNode,
} from '@superfaceai/ast';

import { UnexpectedError } from '../../internal/errors';
import {
MapInterpreter,
ProfileParameterValidator,
Expand All @@ -14,9 +13,7 @@ import { err, ok, Result } from '../../lib';
import { Config } from '../config';
import { fetchMapAST } from './registry';

function forceCast<T>(_: unknown): _ is T {
return true;
}
function forceCast<T>(_: unknown): asserts _ is T {}

export class BoundProvider {
private profileValidator: ProfileParameterValidator;
Expand All @@ -25,19 +22,18 @@ 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);
}

/**
Performs the usecase
*/
async perform<TInput extends NonPrimitive, TResult = unknown>(
input: TInput,
usecase: string
): Promise<Result<TResult, unknown>> {
async perform<
TInput extends NonPrimitive | undefined = undefined,
TResult = unknown
>(usecase: string, input?: TInput): Promise<Result<TResult, unknown>> {
const inputValidation = this.profileValidator.validate(
input,
'input',
Expand Down Expand Up @@ -71,15 +67,9 @@ export class BoundProvider {
return err(resultValidation.error);
}

if (forceCast<TResult>(result.value)) {
return ok(result.value);
}
forceCast<TResult>(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 {
Expand Down
2 changes: 1 addition & 1 deletion src/internal/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
7 changes: 5 additions & 2 deletions src/internal/interpreter/map-interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ function assertUnreachable(node: MapASTNode): never {
throw new UnexpectedError(`Invalid Node kind: ${node.kind}`);
}

export interface MapParameters<TInput extends NonPrimitive> {
export interface MapParameters<
TInput extends NonPrimitive | undefined = undefined
> {
usecase?: string;
auth?: Config['auth'];
baseUrl?: string;
Expand Down Expand Up @@ -93,7 +95,8 @@ interface Stack {
error?: MapInterpreterError;
}

export class MapInterpreter<TInput extends NonPrimitive> implements MapVisitor {
export class MapInterpreter<TInput extends NonPrimitive | undefined>
implements MapVisitor {
private operations: Record<string, OperationDefinitionNode | undefined> = {};
private stack: Stack[] = [];
private ast?: MapDocumentNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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!');
}
Expand Down
23 changes: 14 additions & 9 deletions src/internal/interpreter/profile-parameter-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -96,17 +97,21 @@ export class ProfileParameterValidator implements ProfileVisitor {
kind: ProfileParameterKind,
usecase: string
): Result<undefined, ProfileParameterError> {
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(
Expand Down Expand Up @@ -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))
) {
Expand Down

0 comments on commit c0988c2

Please sign in to comment.