Skip to content

Commit

Permalink
feat: Remove Redundant Initial State, Ensure Post-Transition Executio…
Browse files Browse the repository at this point in the history
…n, and Update Naming (#226)

Co-authored-by: Mohammad Honarvar <[email protected]>
  • Loading branch information
alimd and mohammadhonarvar authored Nov 6, 2024
2 parents 4952c4c + a0c4014 commit f58f80c
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 107 deletions.
4 changes: 2 additions & 2 deletions packages/context/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@
"clean": "rm -rfv dist *.tsbuildinfo"
},
"dependencies": {
"@alwatr/nanolib": "^5.0.0",
"@alwatr/nanolib": "^5.1.0",
"@alwatr/observable": "workspace:^"
},
"devDependencies": {
"@alwatr/nano-build": "^5.0.0",
"@alwatr/prettier-config": "^5.0.0",
"@alwatr/tsconfig-base": "^5.0.0",
"@alwatr/type-helper": "^5.0.0",
"@types/node": "^22.8.6",
"@types/node": "^22.9.0",
"jest": "^29.7.0",
"typescript": "^5.6.3"
}
Expand Down
4 changes: 2 additions & 2 deletions packages/fetch-state-machine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@
},
"dependencies": {
"@alwatr/fsm": "workspace:^",
"@alwatr/nanolib": "^5.0.0"
"@alwatr/nanolib": "^5.1.0"
},
"devDependencies": {
"@alwatr/nano-build": "^5.0.0",
"@alwatr/prettier-config": "^5.0.0",
"@alwatr/tsconfig-base": "^5.0.0",
"@alwatr/type-helper": "^5.0.0",
"@types/node": "^22.8.6",
"@types/node": "^22.9.0",
"jest": "^29.7.0",
"typescript": "^5.6.3"
}
Expand Down
26 changes: 12 additions & 14 deletions packages/fetch-state-machine/src/base.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import {
AlwatrFluxStateMachineBase,
type StateRecord,
type ActionRecord,
type AlwatrFluxStateMachineConfig
} from '@alwatr/fsm';
import {AlwatrFluxStateMachineBase, type StateRecord, type ActionRecord, type AlwatrFluxStateMachineConfig} from '@alwatr/fsm';
import {packageTracer, fetch, type FetchOptions} from '@alwatr/nanolib';

__dev_mode__: packageTracer.add(__package_name__, __package_version__);

export type ServerRequestState = 'initial' | 'loading' | 'failed' | 'complete';
export type ServerRequestEvent = 'request' | 'requestFailed' | 'requestSucceeded';
export type ServerRequestEvent = 'request' | 'request_failed' | 'request_succeeded';

export type {FetchOptions};

export interface AlwatrFetchStateMachineConfig<S extends string> extends AlwatrFluxStateMachineConfig<S> {
export interface AlwatrFetchStateMachineConfig<S extends string> extends Omit<AlwatrFluxStateMachineConfig<S>, 'initialState'> {
fetch: Partial<FetchOptions>;
}

Expand All @@ -30,8 +25,8 @@ export abstract class AlwatrFetchStateMachineBase<
request: 'loading',
},
loading: {
requestFailed: 'failed',
requestSucceeded: 'complete',
request_failed: 'failed',
request_succeeded: 'complete',
},
failed: {
request: 'loading',
Expand All @@ -42,12 +37,15 @@ export abstract class AlwatrFetchStateMachineBase<
} as StateRecord<ServerRequestState | ExtraState, ServerRequestEvent | ExtraEvent>;

protected override actionRecord_ = {
on_loading_enter: this.requestAction_,
on_state_loading_enter: this.requestAction_,
} as ActionRecord<ServerRequestState | ExtraState, ServerRequestEvent | ExtraEvent>;

constructor(config: AlwatrFetchStateMachineConfig<ServerRequestState | ExtraState>) {
config.loggerPrefix ??= 'fetch-state-machine';
super(config);
super({
...config,
initialState: 'initial',
});
this.baseFetchOptions_ = config.fetch;
}

Expand Down Expand Up @@ -85,12 +83,12 @@ export abstract class AlwatrFetchStateMachineBase<

protected requestSucceeded_(): void {
this.logger_.logMethod?.('requestSucceeded_');
this.transition_('requestSucceeded');
this.transition_('request_succeeded');
}

protected requestFailed_(error: Error): void {
this.logger_.error('requestFailed_', 'fetch_failed', error);
this.transition_('requestFailed');
this.transition_('request_failed');
}

protected setFetchOptions_(options?: Partial<FetchOptions>): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/flux/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"@alwatr/prettier-config": "^5.0.0",
"@alwatr/tsconfig-base": "^5.0.0",
"@alwatr/type-helper": "^5.0.0",
"@types/node": "^22.8.6",
"@types/node": "^22.9.0",
"jest": "^29.7.0",
"typescript": "^5.6.3"
}
Expand Down
4 changes: 2 additions & 2 deletions packages/fsm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@
"clean": "rm -rfv dist *.tsbuildinfo"
},
"dependencies": {
"@alwatr/nanolib": "^5.0.0",
"@alwatr/nanolib": "^5.1.0",
"@alwatr/observable": "workspace:^"
},
"devDependencies": {
"@alwatr/nano-build": "^5.0.0",
"@alwatr/prettier-config": "^5.0.0",
"@alwatr/tsconfig-base": "^5.0.0",
"@alwatr/type-helper": "^5.0.0",
"@types/node": "^22.8.6",
"@types/node": "^22.9.0",
"jest": "^29.7.0",
"typescript": "^5.6.3"
}
Expand Down
35 changes: 19 additions & 16 deletions packages/fsm/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,24 @@ export abstract class AlwatrFluxStateMachineBase<S extends string, E extends str
constructor(config: AlwatrFluxStateMachineConfig<S>) {
config.loggerPrefix ??= 'flux-state-machine';
super(config);
this.message_ = {state: this.initialState_ = config.initialState};

this.initialState_ = config.initialState;
this.message_ = {state: this.initialState_};
this.resetToInitialState_();
}

/**
* Reset machine to initial state without notify.
*/
protected resetToInitialState_(): void {
this.logger_.logMethod?.('resetToInitialState_');
const from = this.message_.state;
this.message_ = {state: this.initialState_};
this.postTransition__({
from,
event: 'reset',
to: this.initialState_,
});
}

/**
Expand All @@ -54,7 +63,7 @@ export abstract class AlwatrFluxStateMachineBase<S extends string, E extends str
*/
protected async transition_(event: E): Promise<void> {
const fromState = this.message_.state;
const toState = this.stateRecord_[fromState]?.[event] ?? this.stateRecord_._all?.[event];
const toState = this.stateRecord_[fromState]?.[event];

this.logger_.logMethodArgs?.('transition_', {fromState, event, toState});

Expand All @@ -70,7 +79,7 @@ export abstract class AlwatrFluxStateMachineBase<S extends string, E extends str

if ((await this.shouldTransition_(eventDetail)) !== true) return;

this.notify_({state: toState});
this.notify_({state: toState}); // message update but notify event delayed after execActions.

this.postTransition__(eventDetail);
}
Expand All @@ -81,28 +90,22 @@ export abstract class AlwatrFluxStateMachineBase<S extends string, E extends str
private async postTransition__(eventDetail: StateEventDetail<S, E>): Promise<void> {
this.logger_.logMethodArgs?.('_transitioned', eventDetail);

await this.execAction__(`on_${eventDetail.event}`, eventDetail);
await this.execAction__(`on_event_${eventDetail.event}`, eventDetail);

if (eventDetail.from !== eventDetail.to) {
await this.execAction__(`on_state_exit`, eventDetail);
await this.execAction__(`on_${eventDetail.from}_exit`, eventDetail);
await this.execAction__(`on_state_enter`, eventDetail);
await this.execAction__(`on_${eventDetail.to}_enter`, eventDetail);
await this.execAction__(`on_any_state_exit`, eventDetail);
await this.execAction__(`on_state_${eventDetail.from}_exit`, eventDetail);
await this.execAction__(`on_any_state_enter`, eventDetail);
await this.execAction__(`on_state_${eventDetail.to}_enter`, eventDetail);
}

if (Object.hasOwn(this, `on_${eventDetail.from}_${eventDetail.event}`)) {
this.execAction__(`on_${eventDetail.from}_${eventDetail.event}`, eventDetail);
}
else {
// The action `all_eventName` is executed only if the action `fromState_eventName` is not defined.
this.execAction__(`on_all_${eventDetail.event}`, eventDetail);
}
this.execAction__(`on_state_${eventDetail.from}_event_${eventDetail.event}`, eventDetail);
}

/**
* Execute action name if defined in _actionRecord.
*/
private execAction__(name: ActionName<S, E>, eventDetail: StateEventDetail<S, E>): MaybePromise<void> {
private execAction__(name: ActionName<S, E | 'reset'>, eventDetail: StateEventDetail<S, E>): MaybePromise<void> {
const actionFn = this.actionRecord_[name];
if (typeof actionFn === 'function') {
this.logger_.logMethodArgs?.('_$execAction', name);
Expand Down
23 changes: 11 additions & 12 deletions packages/fsm/src/type.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
export interface StateEventDetail<S, E> {
export interface StateEventDetail<S extends string, E extends string> {
from: S;
event: E;
event: E | 'reset';
to: S;
}

export type StateRecord<S extends string, E extends string> = Partial<Record<S | '_all', Partial<Record<E, S>>>>;
export type StateRecord<S extends string, E extends string> = Partial<Record<S, Partial<Record<E | 'reset', S>>>>;

export type Action<S extends string, E extends string> = (eventDetail?: StateEventDetail<S, E>) => MaybePromise<void>;
export type Action<S extends string, E extends string> = (eventDetail?: StateEventDetail<S, E | 'reset'>) => MaybePromise<void>;

export type ActionName<S extends string, E extends string> =
| `on_${E}`
| `on_state_exit`
| `on_state_enter`
| `on_${S}_exit`
| `on_${S}_enter`
| `on_${S}_${E}`
| `on_all_${E}`;
| `on_event_${E}`
| `on_any_state_exit`
| `on_any_state_enter`
| `on_state_${S}_exit`
| `on_state_${S}_enter`
| `on_state_${S}_event_${E}`;

export type ActionRecord<S extends string, E extends string> = Partial<Record<ActionName<S, E>, Action<S, E>>>;
export type ActionRecord<S extends string, E extends string> = Partial<Record<ActionName<S, E | 'reset'>, Action<S, E | 'reset'>>>;
4 changes: 2 additions & 2 deletions packages/observable/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@
"clean": "rm -rfv dist *.tsbuildinfo"
},
"dependencies": {
"@alwatr/nanolib": "^5.0.0"
"@alwatr/nanolib": "^5.1.0"
},
"devDependencies": {
"@alwatr/nano-build": "^5.0.0",
"@alwatr/prettier-config": "^5.0.0",
"@alwatr/tsconfig-base": "^5.0.0",
"@alwatr/type-helper": "^5.0.0",
"@types/node": "^22.8.6",
"@types/node": "^22.9.0",
"jest": "^29.7.0",
"typescript": "^5.6.3"
}
Expand Down
4 changes: 2 additions & 2 deletions packages/observable/src/observable.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {createLogger, packageTracer} from '@alwatr/nanolib';
import {createLogger, packageTracer, type AlwatrLogger} from '@alwatr/nanolib';

import type {SubscribeOptions, ListenerCallback, Observer, SubscribeResult, AlwatrObservableInterface} from './type.js';

Expand All @@ -11,7 +11,7 @@ export interface AlwatrObservableConfig {

export abstract class AlwatrObservable<T extends DictionaryOpt = DictionaryOpt> implements AlwatrObservableInterface<T> {
protected name_;
protected logger_;
protected logger_: AlwatrLogger;
protected message_?: T;
protected observers__: Observer<this, T>[] = [];

Expand Down
4 changes: 2 additions & 2 deletions packages/remote-context/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@
},
"dependencies": {
"@alwatr/fetch-state-machine": "workspace:^",
"@alwatr/nanolib": "^5.0.0"
"@alwatr/nanolib": "^5.1.0"
},
"devDependencies": {
"@alwatr/nano-build": "^5.0.0",
"@alwatr/prettier-config": "^5.0.0",
"@alwatr/tsconfig-base": "^5.0.0",
"@alwatr/type-helper": "^5.0.0",
"@types/node": "^22.8.6",
"@types/node": "^22.9.0",
"jest": "^29.7.0",
"typescript": "^5.6.3"
}
Expand Down
36 changes: 18 additions & 18 deletions packages/remote-context/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import {packageTracer} from '@alwatr/nanolib';

__dev_mode__: packageTracer.add(__package_name__, __package_version__);

type ExtraState = 'offlineCheck' | 'reloading' | 'reloadingFailed';
type ExtraState = 'offline_check' | 'reloading' | 'reloading_failed';
export type ServerContextState = ServerRequestState | ExtraState;

type ExtraEvent = 'cacheNotFound';
type ExtraEvent = 'cache_not_found';
export type ServerContextEvent = ServerRequestEvent | ExtraEvent;

export type AlwatrRemoteContextStateMachineConfig = AlwatrFetchStateMachineConfig<ServerContextState>;
Expand All @@ -28,37 +28,37 @@ export abstract class AlwatrRemoteContextStateMachineBase<T extends Json = Json>

this.stateRecord_ = {
initial: {
request: 'offlineCheck',
request: 'offline_check',
},
/**
* Just check offline cache data before online request.
*/
offlineCheck: {
requestFailed: 'failed',
cacheNotFound: 'loading',
requestSucceeded: 'reloading',
offline_check: {
request_failed: 'failed',
cache_not_found: 'loading',
request_succeeded: 'reloading',
},
/**
* First loading without any cached context.
*/
loading: {
requestFailed: 'failed',
requestSucceeded: 'complete',
request_failed: 'failed',
request_succeeded: 'complete',
},
/**
* First loading failed without any cached context.
*/
failed: {
request: 'loading', // //TODO: why offlineCheck? should be loading!
request: 'loading', // //TODO: why offline_check? should be loading!
},
reloading: {
requestFailed: 'reloadingFailed',
requestSucceeded: 'complete',
request_failed: 'reloading_failed',
request_succeeded: 'complete',
},
/**
* Reloading failed with previously cached context exist.
*/
reloadingFailed: {
reloading_failed: {
request: 'reloading',
},
complete: {
Expand All @@ -67,10 +67,10 @@ export abstract class AlwatrRemoteContextStateMachineBase<T extends Json = Json>
};

this.actionRecord_ = {
on_offlineCheck_enter: this.offlineRequestAction_,
on_loading_enter: this.onlineRequestAction_,
on_reloading_enter: this.onlineRequestAction_,
on_requestSucceeded: this.updateContextAction_,
on_state_offline_check_enter: this.offlineRequestAction_,
on_state_loading_enter: this.onlineRequestAction_,
on_state_reloading_enter: this.onlineRequestAction_,
on_event_request_succeeded: this.updateContextAction_,
};
}

Expand Down Expand Up @@ -101,7 +101,7 @@ export abstract class AlwatrRemoteContextStateMachineBase<T extends Json = Json>
this.logger_.logMethod?.('requestFailed_');

if (error.message === 'fetch_cache_not_found') {
this.transition_('cacheNotFound');
this.transition_('cache_not_found');
}
else {
super.requestFailed_(error);
Expand Down
4 changes: 2 additions & 2 deletions packages/signal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@
"clean": "rm -rfv dist *.tsbuildinfo"
},
"dependencies": {
"@alwatr/nanolib": "^5.0.0",
"@alwatr/nanolib": "^5.1.0",
"@alwatr/observable": "workspace:^"
},
"devDependencies": {
"@alwatr/nano-build": "^5.0.0",
"@alwatr/prettier-config": "^5.0.0",
"@alwatr/tsconfig-base": "^5.0.0",
"@alwatr/type-helper": "^5.0.0",
"@types/node": "^22.8.6",
"@types/node": "^22.9.0",
"jest": "^29.7.0",
"typescript": "^5.6.3"
}
Expand Down
Loading

0 comments on commit f58f80c

Please sign in to comment.