Skip to content

Commit

Permalink
feat: update unit types
Browse files Browse the repository at this point in the history
  • Loading branch information
izatop committed May 25, 2021
1 parent 55fa528 commit 6a7124c
Show file tree
Hide file tree
Showing 53 changed files with 244 additions and 297 deletions.
50 changes: 25 additions & 25 deletions packages/app/src/Application.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
import {ApplyContext, Context, ContextArg, IContext, unit, Unit} from "@bunt/unit";
import {ActionAny, ApplyContext, Context, ContextArg, unit, Unit} from "@bunt/unit";
import {assert, isDefined, logger, Logger} from "@bunt/util";
import {ActionResponse, IRequest, MatchRoute} from "./interfaces";
import {ActionResponse, IRequest} from "./interfaces";
import {IRoute, RouteNotFound} from "./Route";

export class Application<C extends IContext> {
export class Application<C extends Context> {
@logger
protected logger!: Logger;

protected readonly unit: Unit<C>;
protected readonly route: IRoute[] = [];
readonly #unit: Unit<C>;
readonly #routes: IRoute<ActionAny<C>>[] = [];

constructor(u: Unit<C>, routes: MatchRoute<C, IRoute>[] = []) {
this.unit = u;
constructor(u: Unit<C>, routes: IRoute<ActionAny<C>>[] = []) {
this.#unit = u;

if (routes.length > 0) {
routes.forEach((route) => this.add(route));
}
}

public get context(): C {
return this.unit.context;
public get context(): ApplyContext<C> {
return this.#unit.context;
}

public get size(): number {
return this.route.length;
return this.#routes.length;
}

public static async factory<C extends Context>(
context: ContextArg<C>,
routes: MatchRoute<C, IRoute>[] = []): Promise<Application<ApplyContext<C>>> {
return new this(await unit<C>(context), routes);
routes: IRoute<ActionAny<C>>[] = []): Promise<Application<C>> {
return new this(await unit(context), routes);
}

public add<R extends IRoute>(route: MatchRoute<C, R>): this {
public add(route: IRoute<ActionAny<C>>): this {
this.logger.debug("add", route);
assert(!this.unit.has(route.action), `This route was already added`);
this.unit.add(route.action);
this.route.push(route);
assert(!this.#unit.has(route.action), `This route was already added`);
this.#unit.add(route.action);
this.#routes.push(route);
return this;
}

public remove<R extends IRoute>(route: MatchRoute<C, R>): this {
if (this.unit.has(route.action)) {
public remove(route: IRoute<ActionAny<C>>): this {
if (this.#unit.has(route.action)) {
this.logger.debug("remove", route);
this.unit.remove(route.action);
const index = this.route.findIndex((item) => item === route);
this.route.splice(index, index + 1);
this.#unit.remove(route.action);
const index = this.#routes.findIndex((item) => item === route);
this.#routes.splice(index, index + 1);
}

return this;
}

public async run(request: IRequest): Promise<ActionResponse> {
const route = this.route.find((route) => route.test(request.route));
const route = this.#routes.find((route) => route.test(request.route));
assert(route, () => new RouteNotFound(request.route));

this.logger.debug("match", route);

const unit = this.unit;
const unit = this.#unit;
const state: Record<string, unknown> = {};
const matches = route.match(request.route);
const routeContext = {
Expand All @@ -74,7 +74,7 @@ export class Application<C extends IContext> {
return unit.run(route.action, state);
}

public getRoutes(): IRoute[] {
return this.route;
public getRoutes(): IRoute<ActionAny<C>>[] {
return this.#routes;
}
}
7 changes: 3 additions & 4 deletions packages/app/src/Payload/Payload.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import {FieldSelectType, validate} from "@bunt/input";
import {ActionContext, ActionState} from "@bunt/unit";
import {RouteAction} from "../interfaces";
import {ActionAny, ActionState} from "@bunt/unit";
import {IRouteContext} from "../Route";
import {Resolver} from "./Resolver";

export class Payload<A extends RouteAction> {
export class Payload<A extends ActionAny> {
public readonly resolver: Resolver<A>;
public readonly type: FieldSelectType<ActionState<A>>;

Expand All @@ -13,7 +12,7 @@ export class Payload<A extends RouteAction> {
this.resolver = resolver;
}

public async validate(context: IRouteContext<ActionContext<A>>): Promise<ActionState<A>> {
public async validate(context: IRouteContext<A>): Promise<ActionState<A>> {
return validate<ActionState<A>>(this.type, await this.resolver.resolve(context));
}
}
7 changes: 3 additions & 4 deletions packages/app/src/Payload/Resolver.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import {ActionContext, ActionState} from "@bunt/unit";
import {ActionAny, ActionState} from "@bunt/unit";
import {isFunction, isObject} from "@bunt/util";
import {RouteAction} from "../interfaces";
import {IRouteContext} from "../Route";
import {ResolverResolvers} from "./interfaces";

export class Resolver<A extends RouteAction> {
export class Resolver<A extends ActionAny> {
readonly resolvers: ResolverResolvers<A>;

constructor(resolvers: ResolverResolvers<A>) {
this.resolvers = resolvers;
}

public async resolve(context: IRouteContext<ActionContext<A>>): Promise<ActionState<A>> {
public async resolve(context: IRouteContext<A>): Promise<ActionState<A>> {
const state = {};
const {resolvers} = this;
if (isFunction(resolvers)) {
Expand Down
11 changes: 5 additions & 6 deletions packages/app/src/Payload/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {ActionContext, ActionState} from "@bunt/unit";
import {RouteAction} from "../interfaces";
import {ActionAny, ActionState} from "@bunt/unit";
import {IRouteContext} from "../Route";

export type ResolverFn<A extends RouteAction> = (context: IRouteContext<ActionContext<A>>) => ActionState<A> | unknown;
export type ResolverType<A extends RouteAction> = ActionState<A> | ResolverFn<A>;
export type ResolverFn<A extends ActionAny> = (context: IRouteContext<A>) => ActionState<A> | unknown;
export type ResolverType<A extends ActionAny> = ActionState<A> | ResolverFn<A>;

export type ResolverList<A extends RouteAction> = {
export type ResolverList<A extends ActionAny> = {
[K in keyof ActionState<A>]-?: ResolverType<A>;
};

export type ResolverResolvers<A extends RouteAction> = ResolverFn<A>
export type ResolverResolvers<A extends ActionAny> = ResolverFn<A>
| ResolverList<A>;
13 changes: 6 additions & 7 deletions packages/app/src/Route/Route.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import {ActionCtor} from "@bunt/unit";
import {ILogable, isFunction, isString} from "@bunt/util";
import {RouteAction} from "../interfaces";
import {ActionAny} from "@bunt/unit";
import {Ctor, ILogable, isFunction, isString} from "@bunt/util";
import {Payload} from "../Payload";
import {IRoute, IRouteMatcher, RouteFactory, RouteMatcherFactory, RouteRuleArg} from "./interfaces";
import {RouteRule} from "./RouteRule";

export class Route<A extends RouteAction = RouteAction> implements IRoute<A>, ILogable<{ route: string }> {
export class Route<A extends ActionAny> implements IRoute<A>, ILogable<{ route: string }> {
public readonly route: string;
public readonly action: ActionCtor<A>;
public readonly action: Ctor<A>;
public readonly payload?: Payload<A>;
readonly #matcher: IRouteMatcher;

constructor(matcher: RouteMatcherFactory, action: ActionCtor<A>, rule: RouteRuleArg<A>) {
constructor(matcher: RouteMatcherFactory, action: Ctor<A>, rule: RouteRuleArg<A>) {
const {route, payload} = this.getRuleArgs(rule);
this.route = route;
this.action = action;
Expand All @@ -21,7 +20,7 @@ export class Route<A extends RouteAction = RouteAction> implements IRoute<A>, IL
}

public static create(matcher: RouteMatcherFactory): RouteFactory {
return <A extends RouteAction>(action: ActionCtor<A>, rule: RouteRuleArg<A>) => (
return <A extends ActionAny>(action: Ctor<A>, rule: RouteRuleArg<A>) => (
new Route<A>(matcher, action, rule)
);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/Route/RouteRule.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {FieldSelectType} from "@bunt/input";
import {Action, ActionState} from "@bunt/unit";
import {ActionAny, ActionState} from "@bunt/unit";
import {Payload, Resolver} from "../Payload";

export class RouteRule<A extends Action<any, any>> extends Payload<A> {
export class RouteRule<A extends ActionAny> extends Payload<A> {
public readonly route: string;

constructor(route: string, type: FieldSelectType<ActionState<A>>, resolver: Resolver<A>) {
Expand Down
17 changes: 9 additions & 8 deletions packages/app/src/Route/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {Action, ActionCtor, IContext} from "@bunt/unit";
import {IRequest, RouteAction} from "../interfaces";
import {ActionAny, ActionContext, ActionCtor, ApplyContext, Context} from "@bunt/unit";
import {Ctor} from "@bunt/util";
import {IRequest} from "../interfaces";
import {Payload} from "../Payload";
import {Route} from "./Route";
import {RouteRule} from "./RouteRule";

export interface IRoute<A extends RouteAction = RouteAction> {
export interface IRoute<A extends ActionAny> {
readonly route: string;

readonly action: ActionCtor<A>;
readonly action: ActionCtor<any>;

readonly payload?: Payload<A>;

Expand All @@ -18,15 +19,15 @@ export interface IRoute<A extends RouteAction = RouteAction> {

export type RouteMatcherFactory = IRouteMatcher | ((route: string) => IRouteMatcher);

export type RouteRuleArg<A extends Action<any, any>> = A extends Action<any, infer S>
export type RouteRuleArg<A extends ActionAny> = A extends ActionAny<any, infer S>
? S extends null ? string : RouteRule<A>
: string;

export type RouteFactory = <A extends RouteAction>(action: ActionCtor<A>, rule: RouteRuleArg<A>) => Route<A>;
export type RouteFactory = <A extends ActionAny>(action: Ctor<A>, rule: RouteRuleArg<A>) => Route<A>;

export interface IRouteContext<C extends IContext> {
context: C;
export interface IRouteContext<A extends ActionAny> {
request: IRequest;
context: ApplyContext<ActionContext<A>>;
args: Map<string, string>;
}

Expand Down
12 changes: 0 additions & 12 deletions packages/app/src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {Action, Context, MatchContext} from "@bunt/unit";
import {Promisify} from "@bunt/util";
import {Application} from "./Application";
import {IRoute} from "./Route";

export type ActionResponse = Error
| { stringify(): string }
Expand All @@ -15,16 +13,6 @@ export type ActionResponse = Error
| void
| any;

export type RouteAction = Action<any, any>;

export type MatchRoute<C extends Context, R> = R extends IRoute<infer A>
? A extends Action<infer AC, any, ActionResponse>
? MatchContext<C, AC> extends AC
? R
: ["Action context doesn't match its parent context", C, AC]
: ["Action doesn't satisfy its interface", A]
: never;

export interface IKeyValueMap {
has(name: string): boolean;

Expand Down
4 changes: 2 additions & 2 deletions packages/app/test/src/app/Action/BaseTestAction.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Action} from "@bunt/unit";
import {IBaseContext} from "../Context/BaseContext";
import {BaseContext} from "../Context/BaseContext";

export class BaseTestAction extends Action<IBaseContext, { name: string }> {
export class BaseTestAction extends Action<BaseContext, { name: string }> {
public run(): string {
return `Hello, ${this.state.name}!`;
}
Expand Down
17 changes: 0 additions & 17 deletions packages/app/test/src/app/Action/HelloWorldAction.ts

This file was deleted.

20 changes: 18 additions & 2 deletions packages/app/test/src/app/Action/HelloWorldRoute.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
import {Resolver, RouteRule} from "../../../../src";
import {Bool, Fields, Int, Text, ToNumber} from "@bunt/input";
import {Action} from "@bunt/unit";
import {Resolver, RouteRule} from "../../../../src";
import {route} from "../../route";
import {HelloWorldAction} from "./HelloWorldAction";
import {BaseContext} from "../Context/BaseContext";

interface IHelloWorldActionState {
id: number;
payload: {
name: string;
};
option?: boolean;
}

export class HelloWorldAction extends Action<BaseContext, IHelloWorldActionState> {
public run(): string {
const {payload} = this.state;
return `Hello, ${payload.name}!`;
}
}

export default route(
HelloWorldAction,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {DateTime, Fields, Text, Varchar} from "@bunt/input";
import {Action} from "@bunt/unit";
import {RegexpMatcher, Resolver, Route, RouteRule} from "../../../../src";
import {IBaseContext} from "../Context/BaseContext";
import {BaseContext} from "../Context/BaseContext";

export interface ITestTypeValidationState {
session: string;
Expand All @@ -11,7 +11,7 @@ export interface ITestTypeValidationState {
};
}

class TestInputStateValidationAction extends Action<IBaseContext, ITestTypeValidationState> {
class TestInputStateValidationAction extends Action<BaseContext, ITestTypeValidationState> {
public run(): Record<string, any> {
const {session, payload} = this.state;
return {
Expand Down
2 changes: 0 additions & 2 deletions packages/app/test/src/app/Context/BaseContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ export class BaseContext extends Context {
public version = "1.0.0";
public startAt = new Date();
}

export type IBaseContext = ApplyContext<BaseContext>;
4 changes: 2 additions & 2 deletions packages/cli/src/Action/Command.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {Action, Disposable, Heartbeat, IDisposable, IRunnable, StateType} from "@bunt/unit";
import {Argv, Logger, logger, Program, Promisify} from "@bunt/util";
import {ICommandContext} from "../Context/CommandContext";
import {CommandContext} from "../Context/CommandContext";

export abstract class Command<C extends ICommandContext = ICommandContext,
export abstract class Command<C extends CommandContext,
S extends StateType | null = null> extends Action<C, S, IRunnable>
implements IDisposable, IRunnable {

Expand Down
12 changes: 6 additions & 6 deletions packages/cli/src/Commander.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import {Application, IRoute} from "@bunt/app";
import {Action, ApplyContext, ContextArg, Disposable, Heartbeat, IDisposable, IRunnable} from "@bunt/unit";
import {CommandContext, ICommandContext} from "./Context/CommandContext";
import {Action, ContextArg, Disposable, Heartbeat, IDisposable, IRunnable} from "@bunt/unit";
import {CommandContext} from "./Context/CommandContext";
import {RequestCommand} from "./Request";

export class Commander<C extends ICommandContext> implements IRunnable, IDisposable {
export class Commander<C extends CommandContext> implements IRunnable, IDisposable {
readonly #application: Application<C>;

protected constructor(application: Application<C>) {
this.#application = application;
}

public static async execute<C extends CommandContext>(
context: ContextArg<C>, routes: IRoute<Action<C, any, IRunnable>>[] = []): Promise<Commander<ApplyContext<C>>> {
const command = new this(await Application.factory(context, routes));
context: ContextArg<C>, routes: IRoute<Action<C, any, IRunnable>>[] = []): Promise<Commander<C>> {
const command = new this<C>(await Application.factory<C>(context, routes));
return command.handle();
}

public async handle(): Promise<Commander<any>> {
public async handle(): Promise<Commander<C>> {
const {context} = this.#application;
const request = new RequestCommand(context.program.args);

Expand Down
4 changes: 1 addition & 3 deletions packages/cli/src/Context/CommandContext.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ApplyContext, Context} from "@bunt/unit";
import {Context} from "@bunt/unit";
import {Argv, Program} from "@bunt/util";

export class CommandContext extends Context {
Expand All @@ -13,5 +13,3 @@ export class CommandContext extends Context {
return this.program.args;
}
}

export type ICommandContext = ApplyContext<CommandContext>;
Loading

0 comments on commit 6a7124c

Please sign in to comment.