Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Vitaliy Berekchiyan committed Nov 18, 2023
1 parent cb7a955 commit 3e71399
Show file tree
Hide file tree
Showing 43 changed files with 427 additions and 557 deletions.
56 changes: 28 additions & 28 deletions demo/store.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import {
Effect,
Event,
PersistState,
State,
ComputeState,
DebouncedEvent,
ThrottledEvent,
} from "../src";
import { Event, State, StateManager } from "../src";

type Store = {
changeFirstName: Event<string>;
Expand All @@ -22,13 +14,21 @@ type Store = {
};

const createStore = (): Store => {
const changeFirstName = new Event<string>();
const changeSecondName = new Event<string>();
const changeAge = new Event<number>();
const submitted = new Event();
const resetEvent = new Event();
const debouncedSubmitEvent = new DebouncedEvent(500);
const throttledSubmitEvent = new ThrottledEvent(500);
const demoFormModule = StateManager.initModule("demo form");

const changeFirstName = demoFormModule
.initEvent<string>()
.applyMiddleware((context, next) => {
context.value = context.value.toUpperCase();
next();
});

const changeSecondName = demoFormModule.initEvent<string>();
const changeAge = demoFormModule.initEvent<number>();
const submitted = demoFormModule.initEvent();
const resetEvent = demoFormModule.initEvent();
const debouncedSubmitEvent = demoFormModule.initDebouncedEvent(500);
const throttledSubmitEvent = demoFormModule.initThrottledEvent(500);

debouncedSubmitEvent.subscribe(() => {
console.log("debouncedSubmitEvent called");
Expand All @@ -37,7 +37,7 @@ const createStore = (): Store => {
console.log("throttledSubmitEvent called");
});

const submitEffect = new Effect(
const submitEffect = demoFormModule.initEffect(
(
data: {
firstName: State<string>;
Expand Down Expand Up @@ -82,23 +82,27 @@ const createStore = (): Store => {
console.log(`subscribe | ${data.state}`, data);
});

const firstNameState = new PersistState(
const firstNameState = demoFormModule.initPersistState(
"",
"firstName",
window.sessionStorage
);
const secondNameState = new PersistState(
const secondNameState = demoFormModule.initPersistState(
"",
"lastName",
window.sessionStorage
);
const ageState = new PersistState(1, "age", window.sessionStorage);
const ageState = demoFormModule.initPersistState(
1,
"age",
window.sessionStorage
);

changeFirstName.subscribe((value) => firstNameState.set(value));
changeSecondName.subscribe((value) => secondNameState.set(value));
changeAge.subscribe((value) => ageState.set(value));

const symbolsCountState = new ComputeState(
const symbolsCountState = demoFormModule.initComputedState(
firstNameState,
secondNameState,
(firstName, secondName) =>
Expand All @@ -113,18 +117,14 @@ const createStore = (): Store => {
});
debouncedSubmitEvent.dispatch();
throttledSubmitEvent.dispatch();

// setTimeout(() => {
// submitEffect.release();
// }, 1000);
});

resetEvent.subscribe(() => {
firstNameState.reset();
secondNameState.reset();
ageState.reset();
demoFormModule.resetState();
});

console.log({ StateManager });

return {
changeFirstName,
changeSecondName,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@
],
"repository": "https://github.com/vitlolik/svitore",
"license": "MIT"
}
}
File renamed without changes.
29 changes: 7 additions & 22 deletions src/compute-state.test.ts → src/entities/compute-state.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { describe, it, expect } from "vitest";

import { ComputeState } from "./compute-state";
import { ComputedState } from "./computed-state";
import { State } from "./state";
import { SvitoreError } from "./shared";
import { SvitoreError } from "../utils";

describe("computeState", () => {
it("type", () => {
const state1 = new State(5);
const state2 = new State(5);

const mergedState = new ComputeState(
const mergedState = new ComputedState(
state1,
state2,
(value1, value2) => value1 + value2
Expand All @@ -21,7 +21,7 @@ describe("computeState", () => {
it("initial state", () => {
const state1 = new State("hello");
const state2 = new State("!");
const mergedState = new ComputeState(
const mergedState = new ComputedState(
state1,
state2,
(value1, value2) => value1 + " world" + value2
Expand All @@ -33,7 +33,7 @@ describe("computeState", () => {
it("subscribe to state list", () => {
const state1 = new State("hello");
const state2 = new State("world");
const computed = new ComputeState(
const computed = new ComputedState(
state1,
state2,
(state1, state2) => `${state1} ${state2}`
Expand All @@ -49,7 +49,7 @@ describe("computeState", () => {

it("should be readonly, can not change the state", () => {
const state = new State("world");
const computed = new ComputeState(state, (state) => state.toUpperCase());
const computed = new ComputedState(state, (state) => state.toUpperCase());

try {
computed.set("");
Expand All @@ -63,26 +63,11 @@ describe("computeState", () => {
}
});

it("clone - should clone state with others state list", () => {
const state1 = new State("hello");
const state2 = new State("world");
const computed = new ComputeState(state1, state2, (value1, value2) =>
`${value1} ${value2}`.toUpperCase()
);

const newState1 = new State("foo");
const newState2 = new State("bar");

const cloned = computed.clone([newState1, newState2]);

expect(cloned.get()).toBe("FOO BAR");
});

it("release - should unsubscribe from the state list", () => {
const state1 = new State("hello");
const state2 = new State("world");

const computed = new ComputeState(state1, state2, (value1, value2) =>
const computed = new ComputedState(state1, state2, (value1, value2) =>
`${value1} ${value2}`.toUpperCase()
);

Expand Down
28 changes: 10 additions & 18 deletions src/compute-state.ts → src/entities/computed-state.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { SelectorCallback, SvitoreError } from "./shared";
import { SelectorCallback } from "../types";
import { SvitoreError } from "../utils";
import { State } from "./state";

const throwComputeStateError = (): never => {
throw new SvitoreError("ComputeState is read-only, you must not change it");
const throwComputedStateError = (): never => {
throw new SvitoreError("ComputedState is read-only, you must not change it");
};

class ComputeState<
class ComputedState<
StateList extends ReadonlyArray<State<any>>,
Data
> extends State<Data> {
private stateList: StateList;
private selector: SelectorCallback<StateList, Data>;
private unsubscribeList: (() => void)[] = [];

constructor(...args: [...StateList, SelectorCallback<StateList, Data>]) {
Expand All @@ -21,8 +20,6 @@ class ComputeState<
selector(...(stateList.map((state) => state.get()) as any));

super(getStateData());
this.selector = selector;
this.stateList = stateList;

stateList.forEach((state) => {
this.unsubscribeList.push(
Expand All @@ -31,17 +28,12 @@ class ComputeState<
});
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
set(newState: Data): void {
throwComputeStateError();
set(_newState: Data): never {
return throwComputedStateError();
}

reset(): void {
throwComputeStateError();
}

clone(stateList = this.stateList): ComputeState<StateList, Data> {
return new ComputeState(...[...stateList, this.selector]);
reset(): never {
return throwComputedStateError();
}

release(): void {
Expand All @@ -50,4 +42,4 @@ class ComputeState<
}
}

export { ComputeState };
export { ComputedState };
6 changes: 5 additions & 1 deletion src/debounced-event.ts → src/entities/debounced-event.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { DelayedEvent } from "./delayed-event";
import { DelayedEvent } from "./services";

class DebouncedEvent<Payload = void> extends DelayedEvent<Payload> {
constructor(timeout: number) {
super(timeout);
}

dispatch(payload: Payload): void {
this.clearTimer();
this.timeoutId = setTimeout(() => super.dispatch(payload), this.timeout);
Expand Down
8 changes: 1 addition & 7 deletions src/effect.test.ts → src/entities/effect.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, it, expect, vi } from "vitest";

import { Effect } from "./effect";
import { Entity } from "./shared";
import { Entity } from "./services";

describe("effect", () => {
it("type", () => {
Expand Down Expand Up @@ -111,12 +111,6 @@ describe("effect", () => {
});
});

it("clone - should clone an effect with existing effect function", () => {
const effect = new Effect(() => Promise.resolve());

expect(effect.clone({ isAutoAbort: true })).instanceOf(Entity);
});

it("abort - should abort effect and set change pending state", () => {
const abortListener = vi.fn();
const effect = new Effect(async (_data, abortController) => {
Expand Down
14 changes: 5 additions & 9 deletions src/effect.ts → src/entities/effect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Entity } from "./shared";
import { Entity } from "./services";
import { State } from "./state";

type EffectOptions = {
Expand All @@ -10,16 +10,16 @@ type EffectFunction<Params, Result> = (
abortController: AbortController
) => Promise<Result>;

type NotifyPayload<Params, Result, ErrorType> =
type NotifyPayload<Params, Result, Error> =
| {
state: "fulfilled";
params: Params;
result: Result;
}
| { state: "rejected"; params: Params; error: ErrorType };
| { state: "rejected"; params: Params; error: Error };

class Effect<Params = void, Result = void, ErrorType = any> extends Entity<
NotifyPayload<Params, Result, ErrorType>
class Effect<Params = void, Result = void, Error = any> extends Entity<
NotifyPayload<Params, Result, Error>
> {
private abortController: AbortController | null = null;

Expand All @@ -32,10 +32,6 @@ class Effect<Params = void, Result = void, ErrorType = any> extends Entity<
super();
}

clone(options = this.options): Effect<Params, Result, ErrorType> {
return new Effect(this.effectFunction, options);
}

implement(effectFunction: EffectFunction<Params, Result>): void {
this.effectFunction = effectFunction;
}
Expand Down
34 changes: 34 additions & 0 deletions src/entities/event.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, it, expect, vi } from "vitest";

import { Event } from "./event";
import { Entity } from "./services";

describe("event", () => {
it("type", () => {
const event = new Event();

expect(event).instanceOf(Entity);
});

describe("dispatch - call event with payload", () => {
it("should notify subscribers", () => {
const event = new Event<number>();
const subscriber = vi.fn();
event.subscribe(subscriber);

expect(subscriber).toBeCalledTimes(0);

event.dispatch(1);
expect(subscriber).toBeCalledTimes(1);
expect(subscriber).toHaveBeenCalledWith(1, event);

event.dispatch(2);
expect(subscriber).toBeCalledTimes(2);
expect(subscriber).toHaveBeenCalledWith(2, event);

event.dispatch(0);
expect(subscriber).toBeCalledTimes(3);
expect(subscriber).toHaveBeenCalledWith(0, event);
});
});
});
5 changes: 5 additions & 0 deletions src/entities/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AbstractEvent } from "./services";

class Event<Payload = void> extends AbstractEvent<Payload> {}

export { Event };
11 changes: 11 additions & 0 deletions src/entities/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export { State } from "./state";
export { ComputedState } from "./computed-state";
export { PersistState } from "./persist-state";
export { Event } from "./event";
export { DebouncedEvent } from "./debounced-event";
export { ThrottledEvent } from "./throttled-event";
export { Effect } from "./effect";
export { Reaction } from "./reaction";

export type { EffectFunction } from "./effect";
export type { Middleware } from "./services";
Loading

0 comments on commit 3e71399

Please sign in to comment.