Skip to content

Commit

Permalink
feat(core): add stated field inited and changed interceptor
Browse files Browse the repository at this point in the history
  • Loading branch information
foreleven committed Aug 14, 2019
1 parent 22551b7 commit 6534f5f
Show file tree
Hide file tree
Showing 12 changed files with 319 additions and 115 deletions.
48 changes: 0 additions & 48 deletions src/container/StatedBeanContainer.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/context/StatedBeanContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { StatedBeanContainer } from '../container';
import { StatedBeanContainer } from '../core';

export interface StatedBeanContextValue {
container?: StatedBeanContainer;
Expand Down
27 changes: 9 additions & 18 deletions src/context/StatedBeanProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
import * as React from 'react';

import { ClassType } from '../types/ClassType';
import { IFactory } from '../container';
import { StatedBeanApplication } from '../core';
import { useContainer } from '../hooks';
import { getStatedBeanContext } from './StatedBeanContext';
import { ClassType } from '../types/ClassType';

export interface StatedBeanProviderProps {
types: ClassType[];
beanFactory?: IFactory;
app?: StatedBeanApplication;
children: React.ReactNode | React.ReactNode[] | null;
}

export const StatedBeanProvider: React.FC<StatedBeanProviderProps> = ({
types,
beanFactory,
app,
children,
}) => {
// TODO: update container
const container = useContainer(types, beanFactory);

const StatedBeanContext = getStatedBeanContext();
return (
<StatedBeanContext.Consumer>
{context => {
const parentContainer = context.container;
container.setParent(parentContainer);
const container = useContainer(types, app);

return (
<StatedBeanContext.Provider value={{ container }}>
{children}
</StatedBeanContext.Provider>
);
}}
</StatedBeanContext.Consumer>
return (
<StatedBeanContext.Provider value={{ container }}>
{children}
</StatedBeanContext.Provider>
);
};
60 changes: 60 additions & 0 deletions src/core/EffectContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { StatedBeanMeta, StatedFieldMeta } from '../types';
import { StatedBeanContainer } from './StatedBeanContainer';

export class EffectContext {
private readonly _bean: unknown;
private readonly _beanMeta: StatedBeanMeta;
private readonly _fieldMeta: StatedFieldMeta;
private readonly _oldValue: unknown;
private readonly _container: StatedBeanContainer;

private _value: unknown;

public constructor(
oldValue: unknown,
bean: unknown,
beanMeta: StatedBeanMeta,
fieldMeta: StatedFieldMeta,
container: StatedBeanContainer
) {
this._oldValue = oldValue;
this._bean = bean;
this._beanMeta = beanMeta;
this._fieldMeta = fieldMeta;
this._container = container;
}

get bean(): unknown {
return this._bean;
}

get beanMeta(): StatedBeanMeta {
return this._beanMeta;
}

get fieldMeta(): StatedFieldMeta {
return this._fieldMeta;
}

get oldValue(): unknown {
return this._oldValue;
}

get container(): StatedBeanContainer {
return this._container;
}

setValue(value: any) {
this._value = value;
}

getValue() {
return this._value;
}

toString() {
return `[${this.beanMeta.name}] ${this.fieldMeta.name.toString()} ${String(
this.oldValue
)} => ${String(this._value)}`;
}
}
72 changes: 72 additions & 0 deletions src/core/StatedBeanApplication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { IBeanFactory, DefaultBeanFactory } from './StatedBeanFactory';
import {
StatedInterceptor,
InterceptMethod,
} from '../interceptor/StatedInterceptor';
import { EffectContext } from './EffectContext';

export class StatedBeanApplication {
private _beanFactory: IBeanFactory;
private _interceptors: StatedInterceptor[] = [];

public constructor() {
this._beanFactory = new DefaultBeanFactory();
}

public setBeanFactory(beanFactory: IBeanFactory) {
this._beanFactory = beanFactory;
}

public getBeanFactory(): IBeanFactory {
return this._beanFactory;
}

public setInterceptors(...interceptors: StatedInterceptor[]) {
this._interceptors.push(...interceptors);
}

public getInterceptors() {
return this._interceptors;
}

private invokeInterceptors(method: string, effect: EffectContext) {
let index = -1;
const dispatch = (i: number): Promise<any> => {
if (i <= index) {
return Promise.reject(new Error('next() called multiple times'));
}
index = i;

let interceptor: StatedInterceptor | undefined;
if (i < this._interceptors.length) {
interceptor = this._interceptors[i];
}

let fn =
interceptor !== undefined
? ((interceptor as any)[method] as InterceptMethod)
: undefined;

if (!fn) {
return Promise.resolve();
}

try {
return Promise.resolve(
fn.apply(interceptor, [effect, dispatch.bind(this, i + 1)])
);
} catch (e) {
return Promise.reject(e);
}
};

return dispatch(0);
}

public async interceptStateInit(effect: EffectContext): Promise<void> {
return this.invokeInterceptors('stateInitIntercept', effect);
}
public async interceptStateChange(effect: EffectContext): Promise<void> {
return this.invokeInterceptors('stateChangeIntercept', effect);
}
}
60 changes: 60 additions & 0 deletions src/core/StatedBeanContainer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ClassType } from '../types/ClassType';
import { Event } from '../event';
import { StatedBeanApplication } from './StatedBeanApplication';

export class StatedBeanContainer extends Event {
private _parent?: StatedBeanContainer;
private _app: StatedBeanApplication;
private _types: ClassType[];
private _beans: WeakMap<ClassType<unknown>, unknown>;

public constructor(
types: ClassType[],
parent?: StatedBeanContainer,
app?: StatedBeanApplication
) {
super();

this._types = types;
if (parent === undefined && app === undefined) {
this._app = new StatedBeanApplication();
} else if (app !== undefined) {
this._app = app;
} else if (parent !== undefined) {
this._parent = parent;
this._app = parent.application;
} else {
this._app = new StatedBeanApplication();
}

this._beans = new WeakMap();

this._types.forEach(type => {
const bean = this._app.getBeanFactory().get(type);

this._beans.set(type, bean);
});
}

public getBean<T>(type: ClassType<T>): T | undefined {
let bean = this._beans.get(type);

if (bean === undefined && this.parent) {
bean = this.parent.getBean<T>(type);
}

return bean as T;
}

getAllBeanTypes() {
return this._types;
}

get parent() {
return this._parent;
}

get application() {
return this._app;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ClassType } from '../types/ClassType';

export interface IFactory {
export interface IBeanFactory {
get<T>(type: ClassType): T;
}

export class DefaultFactory implements IFactory {
export class DefaultBeanFactory implements IBeanFactory {
get<T>(type: ClassType): T {
return new type();
}
Expand Down
2 changes: 2 additions & 0 deletions src/container/index.ts → src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './EffectContext';
export * from './StatedBeanApplication';
export * from './StatedBeanContainer';
export * from './StatedBeanFactory';
Loading

0 comments on commit 6534f5f

Please sign in to comment.