Skip to content

Commit

Permalink
Improve scope api.
Browse files Browse the repository at this point in the history
  • Loading branch information
ericmackrodt committed Jan 10, 2019
1 parent 652a3c9 commit 0cdf8a4
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 182 deletions.
3 changes: 2 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export {
Subscription,
Staat,
StateContainerType,
IScope,
} from './types';
export * from './scoped-transformer';
export * from './scope';
export const internals = {
isPromise,
getScope,
Expand Down
70 changes: 70 additions & 0 deletions packages/core/src/scope.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { getScope, isPromise, setScope } from './utils';
import { IScope } from './types';

class Scope<TState> implements IScope<TState, unknown> {
public get path() {
return this.properties;
}

constructor(private properties: string[]) {}

public transformer<TArgs extends any[]>(
definition: (currentScope: unknown, ...args: TArgs) => unknown,
): (currentState: TState, ...args: TArgs) => TState | Promise<TState> {
return (currentState: any, ...args: any) => {
const s = getScope<TState, any>(currentState, this.properties);
const result = definition(s, ...args);
if (isPromise(result)) {
return result.then(promiseResult =>
setScope({ ...currentState }, promiseResult, this.properties),
);
}
return setScope({ ...currentState }, result, this.properties);
};
}
}

function scope<
TState,
K1 extends keyof TState,
K2 extends keyof TState[K1],
K3 extends keyof TState[K1][K2],
K4 extends keyof TState[K1][K2][K3],
K5 extends keyof TState[K1][K2][K3][K4]
>(
scope1: K1,
scope2: K2,
scope3: K3,
scope4: K4,
scope5: K5,
): IScope<TState, TState[K1][K2][K3][K4][K5]>;
function scope<
TState,
K1 extends keyof TState,
K2 extends keyof TState[K1],
K3 extends keyof TState[K1][K2],
K4 extends keyof TState[K1][K2][K3]
>(
scope1: K1,
scope2: K2,
scope3: K3,
scope4: K4,
): IScope<TState, TState[K1][K2][K3][K4]>;
function scope<
TState,
K1 extends keyof TState,
K2 extends keyof TState[K1],
K3 extends keyof TState[K1][K2]
>(scope1: K1, scope2: K2, scope3: K3): IScope<TState, TState[K1][K2][K3]>;
function scope<TState, K1 extends keyof TState, K2 extends keyof TState[K1]>(
scope1: K1,
scope2: K2,
): IScope<TState, TState[K1][K2]>;
function scope<TState, K1 extends keyof TState>(
scope1: K1,
): IScope<TState, TState[K1]>;
function scope<TState>(...properties: string[]): any {
return new Scope<TState>(properties);
}

export { scope };
19 changes: 0 additions & 19 deletions packages/core/src/scoped-transformer.ts

This file was deleted.

51 changes: 9 additions & 42 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,46 +49,13 @@ export interface IScopedTransformerFactory<TState, TScope> {
): (currentState: TState, ...args: TArgs) => TState | Promise<TState>;
}

export interface IScopedTransformer<TState> {
<
K1 extends keyof TState,
K2 extends keyof TState[K1],
K3 extends keyof TState[K1][K2],
K4 extends keyof TState[K1][K2][K3],
K5 extends keyof TState[K1][K2][K3][K4]
>(
prop1: K1,
prop2: K2,
prop3: K3,
prop4: K4,
prop5: K5,
): IScopedTransformerFactory<TState, TState[K1][K2][K3][K4][K5]>;
<
K1 extends keyof TState,
K2 extends keyof TState[K1],
K3 extends keyof TState[K1][K2],
K4 extends keyof TState[K1][K2][K3]
>(
prop1: K1,
prop2: K2,
prop3: K3,
prop4: K4,
): IScopedTransformerFactory<TState, TState[K1][K2][K3][K4]>;
<
K1 extends keyof TState,
K2 extends keyof TState[K1],
K3 extends keyof TState[K1][K2]
>(
prop1: K1,
prop2: K2,
prop3: K3,
): IScopedTransformerFactory<TState, TState[K1][K2][K3]>;
<K1 extends keyof TState, K2 extends keyof TState[K1]>(
prop1: K1,
prop2: K2,
): IScopedTransformerFactory<TState, TState[K1][K2]>;
<K1 extends keyof TState>(prop1: K1): IScopedTransformerFactory<
TState,
TState[K1]
>;
export interface IScope<TState, TScope> {
path: string[];

transformer<TArgs extends any[]>(
definition: (
currentScope: TScope,
...args: TArgs
) => TScope | Promise<TScope>,
): (currentState: TState, ...args: TArgs) => TState | Promise<TState>;
}
12 changes: 6 additions & 6 deletions packages/example/src/calculator-state-definition.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { scopedTransformer } from 'staat';
import { scope } from 'staat';
import { CalculatorState, AppState } from './types';

const transformer = scopedTransformer<AppState>()('calculator');
export const calculatorScope = scope<AppState, 'calculator'>('calculator');

export const initialState: CalculatorState = {
count: 0,
};

export const add = transformer(
(currentState: CalculatorState, val: number): CalculatorState => {
export const add = calculatorScope.transformer(
(currentState, val: number): CalculatorState => {
return {
...currentState,
count: currentState.count + val,
};
},
);

export const subtract = transformer(
(currentState: CalculatorState, val: number): CalculatorState => {
export const subtract = calculatorScope.transformer(
(currentState, val: number): CalculatorState => {
return {
...currentState,
count: currentState.count - val,
Expand Down
4 changes: 2 additions & 2 deletions packages/example/src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import timeTravel from 'staat-timetravel';
import reactStaat from 'staat-react';
import * as calculatorStateDefinition from './calculator-state-definition';
import * as welcomeStateDefinition from './welcome-state-definition';
import { AppState } from './types';

const {
calculatorScope,
initialState: calcInitialState,
...calcTransformers
} = calculatorStateDefinition;
Expand All @@ -20,7 +20,7 @@ const initialState = {
};

const transformers = {
calculator: timeTravel<AppState>()(calcTransformers, 'calculator'),
calculator: timeTravel(calcTransformers, calculatorScope),
welcome: welcomeTransformers,
};

Expand Down
8 changes: 4 additions & 4 deletions packages/example/src/welcome-state-definition.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { scopedTransformer } from 'staat';
import { scope } from 'staat';
import { WelcomeState, AppState } from './types';

export const initialState: WelcomeState = {};

const transformer = scopedTransformer<AppState>()('welcome');
const welcomeScope = scope<AppState, 'welcome'>('welcome');

export const setName = transformer(
(currentState: WelcomeState, name: string) => {
export const setName = welcomeScope.transformer(
(currentState, name: string) => {
return { ...currentState, name };
},
);
80 changes: 44 additions & 36 deletions packages/time-travel/src/time-travel.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import { internals, scopedTransformer } from 'staat';
import { internals, IScope } from 'staat';
import { TimeTravelContainer } from './time-travel-container';
import {
TimeTravelTransformers,
Transformer,
ITimeTravelTransformers,
} from './types';
import { getKeys, asArray } from './utils';
import { TimeTravelTransformers, Transformer } from './types';
import { getKeys } from './utils';

function udpateHistory<TState extends object>(
currentState: TState,
newState: TState,
container: TimeTravelContainer,
scope?: string[],
scope?: IScope<TState, object>,
): TState {
if (scope) {
// TODO: Any here shouldn't affect api's types, but should try to resolve later.
const newScope = internals.getScope<TState, any>(newState, scope);
const newScope = internals.getScope<TState, any>(newState, scope.path);
const currentScope = internals.getScope<TState, TState>(
currentState,
scope,
scope.path,
);
container.setPresent(currentScope, newScope);
} else {
Expand All @@ -34,7 +30,7 @@ function createTimeTravelTransformer<
>(
transformer: Transformer<TState, TArgs>,
container: TimeTravelContainer,
scope?: string[],
scope?: IScope<TState, object>,
) {
return (currentState: TState, ...args: TArgs) => {
const result = transformer(currentState, ...args);
Expand All @@ -47,14 +43,14 @@ function createTimeTravelTransformer<
};
}

function createUndo<TState extends object>(container: TimeTravelContainer) {
return (currentState: TState): TState => {
function createUndo(container: TimeTravelContainer) {
return <TState>(currentState: TState): TState => {
return container.undo(currentState) as TState;
};
}

function createRedo<TState extends object>(container: TimeTravelContainer) {
return (currentState: TState): TState => {
function createRedo(container: TimeTravelContainer) {
return <TState>(currentState: TState): TState | Promise<TState> => {
return container.redo(currentState) as TState;
};
}
Expand All @@ -65,7 +61,7 @@ export function timeTravelTransformers<
>(
transformers: TTransformers,
container: TimeTravelContainer,
scope?: string[],
scope?: IScope<TState, object>,
): TimeTravelTransformers<TState, TTransformers> {
const newTransformers: TimeTravelTransformers<
TState,
Expand All @@ -84,32 +80,44 @@ export function timeTravelTransformers<
{} as Record<keyof TTransformers, Transformer<TState, any[]>>,
) as TimeTravelTransformers<TState, TTransformers>;

const scoped = scope ? scopedTransformer<TState>()(scope as any) : undefined;

newTransformers.undo = scoped
? scoped(createUndo(container))
newTransformers.undo = scope
? scope.transformer(createUndo(container))
: createUndo(container);
newTransformers.redo = scoped
? scoped(createRedo(container))
newTransformers.redo = scope
? scope.transformer(createRedo(container))
: createRedo(container);

return newTransformers;
}

function timeTravel<TState>(): ITimeTravelTransformers<TState> {
return <
TTransformers extends Record<
keyof TTransformers,
Transformer<TState, any[]>
>
>(
transformers: TTransformers,
scope?: string | string[],
) => {
const container = new TimeTravelContainer();
const scopeAsArray = scope ? asArray(scope) : undefined;
return timeTravelTransformers(transformers, container, scopeAsArray);
};
function timeTravel<
TState,
TScope,
TTransformers extends Record<keyof TTransformers, Transformer<TState, any[]>>
>(
transformers: TTransformers,
scope: IScope<TState, TScope>,
): TimeTravelTransformers<TState, TTransformers>;
function timeTravel<
TState extends object,
TTransformers extends Record<
keyof TTransformers,
Transformer<any, any[]>
> = TTransformers
>(transformers: TTransformers): TimeTravelTransformers<TState, TTransformers>;
function timeTravel<
TState extends object,
TTransformers extends Record<keyof TTransformers, Transformer<TState, any[]>>
>(
transformers: TTransformers,
scope?: IScope<TState, object>,
): TimeTravelTransformers<TState, TTransformers> {
const container = new TimeTravelContainer();
return timeTravelTransformers<TState, TTransformers>(
transformers,
container,
scope,
);
}

export default timeTravel;
Loading

0 comments on commit 0cdf8a4

Please sign in to comment.