Socket
Socket
Sign inDemoInstall

@rx-signals/store

Package Overview
Dependencies
Maintainers
1
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rx-signals/store - npm Package Compare versions

Comparing version 2.7.0-rc1 to 2.7.0-rc2

95

CHANGELOG.md

@@ -1,12 +0,25 @@

# 2.7.0
# Changes
### Breaking change (yes as minor version, because it's a simple refactoring)
## 2.7.0
- changed definition for TypeIdentifier: From now on, you have to use getIdentifier<T>() to get your identifiers
### Documentation
# 2.6.2 (2021-09-07)
- **Finally** added the first version of a documentation (not yet complete)!
### Features
- Extended `EffectSuccess` type by `previousInput?` and `previousResult?` to aid in event transforms in some more complex scenarios.
- Extended `SignalsFactory` type by `idsMap` and extended `createSignalsFactory` correspondingly (see documentation).
- Extended `SignalsFactory` by `flattenIds` and extended `createSignalsFactory` correspondingly (see documentation).
### Improvements
- Changed definition for `TypeIdentifier`: From now on, you should always use `getIdentifier<T>()` to get your identifiers
- Improved type definitions for `SignalsFactory` and types it depends on
## 2.6.2 (2021-09-07)
### Fixes
- EffectSuccess interface was missing in the index.ts
- `EffectSuccess` type was missing in the index.ts
- Docstring typos

@@ -16,16 +29,16 @@

- added **completeAllSignals** to store API, to take care of store cleanup (e.g. if the lifetime of a child store ends)
- Added `completeAllSignals()` to store API, to take care of store cleanup (e.g. if the lifetime of a child store ends)
# 2.6.1 (2021-07-23)
## 2.6.1 (2021-07-23)
### Fixes
- The new convenience function createSignalsFactory was missing in the index.ts
- The new convenience function `createSignalsFactory` was missing in the index.ts
# 2.6.0 (2021-07-23)
## 2.6.0 (2021-07-23)
### Fixes
- Fixed a bug for x-typed event sources with subscribeObservableOnlyIfEventIsSubscribed parameter: It was possible that the source was not already switched for one of the sources, when an event was already dispatched after the subscribeObservableOnlyIfEventIsSubscribed event was subscribed.
- Removed all usage of shareReplay, because even with refCount, a case was encountered where shareReplay lead to a memory leak.
- Fixed a bug for x-typed event sources with `subscribeObservableOnlyIfEventIsSubscribed` parameter: It was possible that the source was not already switched for one of the sources, when an event was already dispatched after the `subscribeObservableOnlyIfEventIsSubscribed` event was subscribed.
- Removed all usage of `shareReplay`, because even with `refCount`, a case was encountered where `shareReplay` lead to a memory leak.

@@ -37,3 +50,3 @@ ### Improvements

# 2.5.5 (2021-07-08)
## 2.5.5 (2021-07-08)

@@ -44,3 +57,3 @@ ### Features

# 2.5.4 (2021-07-07)
## 2.5.4 (2021-07-07)

@@ -51,15 +64,15 @@ ### Features

# 2.5.3 (2021-07-01)
## 2.5.3 (2021-07-01)
### Improvements
- Added also the exported low-level-type-symbols to index.ts, to help Typescript recognizing matching types
- Added also the exported low-level-type-symbols to index.ts
# 2.5.2 (2021-06-30)
## 2.5.2 (2021-06-30)
### Features
- Signals factories now expose their internal effect result events. Subscribing to the corresponding event streams will NOT subscribe the behaviors and thus, no effects will be triggered by simply subscribing to the streams.
- Signals factories now expose their internal effect result events. Subscribing to the corresponding event streams will **NOT** subscribe the behaviors and thus, no effects will be triggered by simply subscribing to the streams.
# 2.5.1 (2021-06-30)
## 2.5.1 (2021-06-30)

@@ -70,30 +83,30 @@ ### Features

# 2.5.0 (2021-06-30)
## 2.5.0 (2021-06-30)
### Features
- **prepareInputWithResultSignals** and **prepareValidatedInputWithResultSignals**: Added new option **withTriggerEvent**. If set true, the result effect will only be triggered, when the corresponding event is dispatched (the event is just an alias for the invalidation event).
- All signals factories now provide an event stream for unhandled effect errors. Subscribing to these streams will NOT subscribe the behaviors (thus, you can always subscribe with your generic error handler without triggering the effects unless you subscribe the behaviors of these factories).
- `prepareInputWithResultSignals` and `prepareValidatedInputWithResultSignals`: Added new option `withTriggerEvent`. If set true, the result effect will only be triggered, when the corresponding event is dispatched (the event is just an alias for the invalidation event).
- All signals factories now provide an event stream for unhandled effect errors. Subscribing to these streams will **NOT** subscribe the behaviors (thus, you can always subscribe with your generic error handler without triggering the effects unless you subscribe the behaviors of these factories).
# 2.4.2 (2021-06-28)
## 2.4.2 (2021-06-28)
### Fixes
- **prepareValidatedInputWithResultSignals** a custom input equals function will now also be used on the validated input (preventing a retriggered result effect upon changed input)
- `prepareValidatedInputWithResultSignals` a custom input equals function will now also be used on the validated input (preventing a retriggered result effect upon changed input)
# 2.4.1 (2021-06-25)
## 2.4.1 (2021-06-25)
### Fixes
- Fixed module exports, to make everything available under @rx-signals/store
- Fixed module exports, to make everything available under _@rx-signals/store_
# 2.4.0 (2021-06-24)
## 2.4.0 (2021-06-24)
### Features
- **prepareValidatedInputSignals** Get a factory for signals representing a validated input.
- **prepareInputWithResultSignals** Get a factory for signals representing a result for an input and result invalidation.
- **prepareValidatedInputWithResultSignals** Get a factory for signals representing a result for a validated input.
- `prepareValidatedInputSignals` Get a factory for signals representing a validated input.
- `prepareInputWithResultSignals` Get a factory for signals representing a result for an input and result invalidation.
- `prepareValidatedInputWithResultSignals` Get a factory for signals representing a result for a validated input.
# 2.3.0 (2021-06-17)
## 2.3.0 (2021-06-17)

@@ -103,6 +116,6 @@ ### Features

**First store utility functions** This minor version brings the first utility functions to help reducing boilerplate code for standard patterns.
- **getIdentifier** A simple convenience function to create store type identifiers.
- **prepareEffectSignals** A facory function that generalizes all the store setup for the case where you have an input model, an effect taking the input and producing a result model, as well as providing loading behavior and invalidation (refresh) event.
- `getIdentifier` A simple convenience function to create store type identifiers.
- `prepareEffectSignals` A facory function that generalizes all the store setup for the case where you have an input model, an effect taking the input and producing a result model, as well as providing loading behavior and invalidation (refresh) event.
# 2.2.3 (2021-05-05)
## 2.2.3 (2021-05-05)

@@ -113,27 +126,27 @@ ### Fixes

# 2.2.2 (2021-04-03)
## 2.2.2 (2021-04-03)
### Dependencies
- **Made rxjs a peer dependency (was a dependency before) and relaxed the version requirement to ^6.4.0 (though there should be no reason not to upgrade your project to the latest 6.x version)**
- Made rxjs a peer dependency (was a dependency before) and relaxed the version requirement to ^6.4.0 (though there should be no reason not to upgrade your project to the latest 6.x version)
# 2.2.0 (2021-04-01)
## 2.2.0 (2021-04-01)
### Features
- **Instead of passing an initial value, all corresponding methods now also accept a callback providing the initial value.** This is especially useful for lazy behaviors, as you can now also perform the initial value creation lazily (of course you could already do this before, by not using initialValue, but instead piping your behavior observable with a startWith(initialValue)).
- Instead of passing an initial value, all corresponding methods now also accept a callback providing the initial value. This is especially useful for lazy behaviors, as you can now also perform the initial value creation lazily (of course you could already do this before, by not using initialValue, but instead piping your behavior observable with a startWith(initialValue)).
### Documentation
- **Finally added at least some doc strings for the store API**
- Finally added at least some doc strings for the store API
# 2.1.1 (2021-03-26)
## 2.1.1 (2021-03-26)
### Fixes
- No longer passing undefined as initial value to SourceObservable, but the semantically more correct NO_VALUE (This was not really a bug, cause passing undefined or NO_VALUE currently made no difference at runtime. However, it might have lead to a bug in the future, when modifying SourceObservable without having this in mind.)
- No longer passing undefined as initial value to `SourceObservable`, but the semantically more correct `NO_VALUE` (This was not really a bug, cause passing undefined or `NO_VALUE` currently made no difference at runtime. However, it might have lead to a bug in the future, when modifying `SourceObservable` without having this in mind.)
# 2.1.0 (2021-03-25)
## 2.1.0 (2021-03-25)
- **This is the first official (non-RC) release** (though documentation is still missing)
- See the git history of CHANGELOG.md, if you're interested in the changes for all the previous RC versions

@@ -25,5 +25,3 @@ "use strict";

signalNext() {
(0, rxjs_1.of)(null)
.pipe((0, operators_1.delay)(1, rxjs_1.asyncScheduler))
.subscribe(() => {
setTimeout(() => {
const queueLength = this.queueArray.length;

@@ -38,3 +36,3 @@ // eslint-disable-next-line no-plusplus

}
});
}, 0);
}

@@ -41,0 +39,0 @@ }

@@ -30,3 +30,3 @@ "use strict";

try {
return config.effect(input, store, previousInput, previousResult);
return config.effect(input, store, previousInput, previousResult).pipe((0, operators_1.take)(1));
}

@@ -83,2 +83,4 @@ catch (error) {

resultInput: input,
previousInput: resultState.resultInput,
previousResult: resultState.result,
},

@@ -120,3 +122,3 @@ })), (0, operators_1.catchError)(error => (0, rxjs_1.of)({

setup,
signals: (config.withTrigger ? ids : withoutTriggerID),
ids: (config.withTrigger ? ids : withoutTriggerID),
};

@@ -123,0 +125,0 @@ };

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getValidatedInputWithResultSignalsFactory = exports.NO_VALUE = exports.getIdentifier = exports.Store = exports.signalsFactoryMap = exports.signalsFactoryBind = exports.createSignalsFactory = exports.getEffectSignalsFactory = void 0;
exports.getValidatedInputWithResultSignalsFactory = exports.NO_VALUE = exports.getIdentifier = exports.Store = exports.createSignalsFactory = exports.getEffectSignalsFactory = void 0;
var effect_signals_factory_1 = require("./effect-signals-factory");

@@ -8,4 +8,2 @@ Object.defineProperty(exports, "getEffectSignalsFactory", { enumerable: true, get: function () { return effect_signals_factory_1.getEffectSignalsFactory; } });

Object.defineProperty(exports, "createSignalsFactory", { enumerable: true, get: function () { return signals_factory_1.createSignalsFactory; } });
Object.defineProperty(exports, "signalsFactoryBind", { enumerable: true, get: function () { return signals_factory_1.signalsFactoryBind; } });
Object.defineProperty(exports, "signalsFactoryMap", { enumerable: true, get: function () { return signals_factory_1.signalsFactoryMap; } });
var store_1 = require("./store");

@@ -12,0 +10,0 @@ Object.defineProperty(exports, "Store", { enumerable: true, get: function () { return store_1.Store; } });

"use strict";
/* eslint-disable @typescript-eslint/no-use-before-define */
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSignalsFactory = exports.signalsFactoryBind = exports.signalsFactoryMap = void 0;
/**
* A utility function that implements fmap for signal factories. However, instead of using this
* low-level function, in most cases you should just use the createSignalsFactory utility function.
*
* @template SignalsType1 - specifies the signals type for the input factory
* @template SignalsType2 - specifies the signals type for the resulting factory
* @param {SignalsFactory<SignalsType1>} factory1 - the input factory
* @param {function} mapper - the function mapping from Signals<SignalsType1> to Signals<SignalsType2>
* @returns {SignalsFactory<SignalsType2>} the resulting factory
*/
exports.createSignalsFactory = void 0;
const signalsFactoryFlattenComposedIds = (factory) => signalsFactoryIdsMap(factory, (ids) => flattenSignalIds(ids));
const signalsFactoryIdsMap = (factory1, mapper) => {
const fmapper = s => ({
ids: mapper(s.ids),
setup: s.setup,
});
const build = () => fmapper(factory1.build());
let factory2;
const fmap = (mapper2) => signalsFactoryMap(factory2, mapper2);
const idsMap = (mapper2) => signalsFactoryIdsMap(factory2, mapper2);
const bind = (mapper2) => signalsFactoryBind(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build,
bind,
fmap,
idsMap,
flattenIds,
};
return factory2;
};
const signalsFactoryMap = (factory1, mapper) => {
const newBuild = () => mapper(factory1.build());
const build = () => mapper(factory1.build());
let factory2;
const newMap = (mapper2) => (0, exports.signalsFactoryMap)(factory2, mapper2);
const newBind = (mapper2) => (0, exports.signalsFactoryBind)(factory2, mapper2);
const fmap = (mapper2) => signalsFactoryMap(factory2, mapper2);
const idsMap = (mapper2) => signalsFactoryIdsMap(factory2, mapper2);
const bind = (mapper2) => signalsFactoryBind(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build: newBuild,
bind: newBind,
fmap: newMap,
build,
bind,
fmap,
idsMap,
flattenIds,
};
return factory2;
};
exports.signalsFactoryMap = signalsFactoryMap;
/**
* A utility function that implements bind for signal factories. However, instead of using this
* low-level function, in most cases you should just use the createSignalsFactory utility function.
*
* @template SignalsType1 - specifies the signals type for the input factory
* @template SignalsType2 - specifies the signals type for the resulting factory
* @param {SignalsFactory<SignalsType1>} factory1 - the input factory
* @param {function} mapper - the function mapping from Signals<SignalsType1> to SignalsFactory<SignalsType2>
* @returns {SignalsFactory<SignalsType2>} the resulting factory
*/
const flattenIdsImpl = (ids) => {
if (ids.ids1 && ids.ids2) {
const result = Object.assign({}, ids);
const { ids1, ids2 } = result;
delete result.ids1;
delete result.ids2;
Object.entries(ids1).forEach(([k, v]) => {
let kNew = k;
while (result[kNew]) {
kNew += '_1';
}
result[kNew] = v;
});
Object.entries(ids2).forEach(([k, v]) => {
let kNew = k;
while (result[kNew]) {
kNew += '_2';
}
result[kNew] = v;
});
// A recursive implementation is trivial, but calculating its corresponding result
// type recursilvely, as of TS 4.4.4, results in:
// 'Type instantiation is excessively deep and possibly infinite.ts(2589)'
// Maybe future TS versions can handle complex type definitions more efficiently
// return flattenIdsImpl(result);
return result;
}
return ids;
};
const flattenSignalIds = (ids) => flattenIdsImpl(ids);
const signalsFactoryBind = (factory1, mapper) => {
const newBuild = () => {
const build = () => {
const s1 = factory1.build();

@@ -48,5 +81,5 @@ const factory2 = mapper(s1);

},
signals: {
signals1: s1.signals,
signals2: s2.signals,
ids: {
ids1: s1.ids,
ids2: s2.ids,
},

@@ -56,25 +89,30 @@ };

let factory2;
const newBind = (mapper2) => (0, exports.signalsFactoryBind)(factory2, mapper2);
const newMap = (mapper2) => (0, exports.signalsFactoryMap)(factory2, mapper2);
const bind = (mapper2) => signalsFactoryBind(factory2, mapper2);
const fmap = (mapper2) => signalsFactoryMap(factory2, mapper2);
const idsMap = (mapper2) => signalsFactoryIdsMap(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build: newBuild,
bind: newBind,
fmap: newMap,
build,
bind,
fmap,
idsMap,
flattenIds,
};
return factory2;
};
exports.signalsFactoryBind = signalsFactoryBind;
/**
* This utility function creates an object that implements the SignalsFactory interface. It should be
* This utility function creates an object that implements the SignalsFactory type. It should be
* used to implement all specific signal factories (by just extending the returned object as required).
* See the implementation of EffectSignalsFactory (which is actually a builder) for an example.
*
* @template SignalsType - specifies the signals type for the factory
* @param {function} build - the function that implements build for SignalsFactory<SignalsType>
* @returns {SignalsFactory<SignalsType>}
* @template T - the concrete SignalIds type type for the factory
* @param {FactoryBuild<T>} build - the function that implements build for SignalsFactory<T>
* @returns {SignalsFactory<T>}
*/
const createSignalsFactory = (build) => {
let factory;
const bind = (mapper) => (0, exports.signalsFactoryBind)(factory, mapper);
const fmap = (mapper) => (0, exports.signalsFactoryMap)(factory, mapper);
const bind = (mapper) => signalsFactoryBind(factory, mapper);
const fmap = (mapper) => signalsFactoryMap(factory, mapper);
const idsMap = (mapper) => signalsFactoryIdsMap(factory, mapper);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory);
factory = {

@@ -84,2 +122,4 @@ build,

fmap,
idsMap,
flattenIds,
};

@@ -86,0 +126,0 @@ return factory;

@@ -71,3 +71,3 @@ "use strict";

* @param {Observable<T>} observable - the source for the behavior
* @param {boolean} subscribeLazy - set this to false, if the behavior should always be subscribed (the Store will subscribe it in that case)
* @param {boolean} subscribeLazy - set this to false, if the behavior should always be subscribed (the Store will subscribe it in that case, immediately turning it into a hot observable)
* @param {T | (() => T) | symbol} initialValueOrValueGetter - the initial value or value getter (for lazy initialization) or symbol NO_VALUE, if there is no initial value (default)

@@ -115,5 +115,5 @@ * @returns {void}

/**
* This adds a reducer to a bahavior. This is meant to be used together with the addState method.
* This adds a reducer to a behavior. This is meant to be used together with the addState method.
* Technically, you can also add reducers to behaviors that were added with one of the addBevavior methods.
* However, this is strongly discouraged and might result in unexpected (literally) behavior.
* However, this is strongly discouraged and might result in unexpected behavior (literally).
*

@@ -129,2 +129,8 @@ * @param {TypeIdentifier<T>} stateIdentifier - the unique identifier for the behavior

}
// connectBehaviorIds<T>(
// sourceIdentifier: TypeIdentifier<T>,
// targetIdentifier: TypeIdentifier<T>,
// ): void {
// this.addLazyBehavior(targetIdentifier, this.getBehavior(sourceIdentifier));
// }
/**

@@ -131,0 +137,0 @@ * This method can be used to remove a reducer from a behavior.

@@ -23,4 +23,4 @@ "use strict";

store.addLazyBehavior(id, (0, rxjs_1.combineLatest)([
store.getBehavior(signals.signals.signals1.combinedBehavior),
store.getBehavior(signals.signals.signals2.combinedBehavior).pipe((0, operators_1.startWith)({
store.getBehavior(signals.ids.ids1.combinedBehavior),
store.getBehavior(signals.ids.ids2.combinedBehavior).pipe((0, operators_1.startWith)({
currentInput: undefined,

@@ -46,3 +46,3 @@ resultInput: undefined,

const factory = validationFactory
.bind(validationSignals => (0, effect_signals_factory_1.getEffectSignalsFactory)((store) => resultInputGetter(store, validationSignals.signals.combinedBehavior, config.isValidationResultValid), config.resultEffect)
.bind(validationSignals => (0, effect_signals_factory_1.getEffectSignalsFactory)((store) => resultInputGetter(store, validationSignals.ids.combinedBehavior, config.isValidationResultValid), config.resultEffect)
.withTrigger()

@@ -56,11 +56,11 @@ .withInitialResult(config.initialResultGetter)

setup,
signals: {
ids: {
combinedBehavior,
validationErrorEvents: signals.signals.signals1.errorEvents,
validationSuccessEvents: signals.signals.signals1.successEvents,
validationInvalidateEvent: signals.signals.signals1.invalidateEvent,
resultErrorEvents: signals.signals.signals2.errorEvents,
resultSuccessEvents: signals.signals.signals2.successEvents,
resultInvalidateEvent: signals.signals.signals2.invalidateEvent,
resultTriggerEvent: signals.signals.signals2.triggerEvent,
validationErrorEvents: signals.ids.ids1.errorEvents,
validationSuccessEvents: signals.ids.ids1.successEvents,
validationInvalidateEvent: signals.ids.ids1.invalidateEvent,
resultErrorEvents: signals.ids.ids2.errorEvents,
resultSuccessEvents: signals.ids.ids2.successEvents,
resultInvalidateEvent: signals.ids.ids2.invalidateEvent,
resultTriggerEvent: signals.ids.ids2.triggerEvent,
},

@@ -74,3 +74,3 @@ };

const factory = validationFactory
.bind(validationSignals => (0, effect_signals_factory_1.getEffectSignalsFactory)((store) => resultInputGetter(store, validationSignals.signals.combinedBehavior, config.isValidationResultValid), config.resultEffect)
.bind(validationSignals => (0, effect_signals_factory_1.getEffectSignalsFactory)((store) => resultInputGetter(store, validationSignals.ids.combinedBehavior, config.isValidationResultValid), config.resultEffect)
.withInitialResult(config.initialResultGetter)

@@ -83,10 +83,10 @@ .withCustomEffectInputEquals(config.resultEffectInputEquals))

setup,
signals: {
ids: {
combinedBehavior,
validationErrorEvents: signals.signals.signals1.errorEvents,
validationSuccessEvents: signals.signals.signals1.successEvents,
validationInvalidateEvent: signals.signals.signals1.invalidateEvent,
resultErrorEvents: signals.signals.signals2.errorEvents,
resultSuccessEvents: signals.signals.signals2.successEvents,
resultInvalidateEvent: signals.signals.signals2.invalidateEvent,
validationErrorEvents: signals.ids.ids1.errorEvents,
validationSuccessEvents: signals.ids.ids1.successEvents,
validationInvalidateEvent: signals.ids.ids1.invalidateEvent,
resultErrorEvents: signals.ids.ids2.errorEvents,
resultSuccessEvents: signals.ids.ids2.successEvents,
resultInvalidateEvent: signals.ids.ids2.invalidateEvent,
},

@@ -93,0 +93,0 @@ };

@@ -1,3 +0,3 @@

import { asyncScheduler, of, Subject } from 'rxjs';
import { delay, mapTo, mergeMap } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { mapTo, mergeMap } from 'rxjs/operators';
export class DelayedEventQueue {

@@ -22,5 +22,3 @@ constructor() {

signalNext() {
of(null)
.pipe(delay(1, asyncScheduler))
.subscribe(() => {
setTimeout(() => {
const queueLength = this.queueArray.length;

@@ -35,3 +33,3 @@ // eslint-disable-next-line no-plusplus

}
});
}, 0);
}

@@ -38,0 +36,0 @@ }

import { Observable } from 'rxjs';
import { SignalsFactory } from './signals-factory';
import { SignalIds, SignalsFactory } from './signals-factory';
import { Store } from './store';

@@ -54,2 +54,4 @@ import { TypeIdentifier } from './store.utils';

* @property {InputType} resultInput - the effect input that lead to the result
* @property {InputType | undefined} previousInput - the input of the previous result, or undefined
* @property {ResultType | undefined} previousResult - the previous result, or undefined
*/

@@ -59,2 +61,4 @@ export declare type EffectSuccess<InputType, ResultType> = Readonly<{

resultInput: InputType;
previousInput?: InputType;
previousResult?: ResultType;
}>;

@@ -114,7 +118,7 @@ /**

*/
export declare type EffectSignalsFactory<InputType, ResultType, SignalsType> = SignalsFactory<SignalsType> & {
export declare type EffectSignalsFactory<InputType, ResultType, T extends SignalIds> = SignalsFactory<T> & {
withTrigger: () => EffectSignalsFactory<InputType, ResultType, TriggeredEffectSignalsType<InputType, ResultType>>;
withInitialResult: (resultGetter?: () => ResultType) => EffectSignalsFactory<InputType, ResultType, SignalsType>;
withEffectDebounce: (debounceMS: number) => EffectSignalsFactory<InputType, ResultType, SignalsType>;
withCustomEffectInputEquals: (effectInputEquals: (a: InputType, b: InputType) => boolean) => EffectSignalsFactory<InputType, ResultType, SignalsType>;
withInitialResult: (resultGetter?: () => ResultType) => EffectSignalsFactory<InputType, ResultType, T>;
withEffectDebounce: (debounceMS: number) => EffectSignalsFactory<InputType, ResultType, T>;
withCustomEffectInputEquals: (effectInputEquals: (a: InputType, b: InputType) => boolean) => EffectSignalsFactory<InputType, ResultType, T>;
};

@@ -144,4 +148,6 @@ /**

resultInput: InputType;
previousInput?: InputType | undefined;
previousResult?: ResultType | undefined;
}>>;
invalidateEvent: TypeIdentifier<void>;
}>>;

@@ -13,3 +13,3 @@ var __rest = (this && this.__rest) || function (s, e) {

import { combineLatest, of, throwError } from 'rxjs';
import { catchError, debounceTime, filter, map, mapTo, switchMap } from 'rxjs/operators';
import { catchError, debounceTime, filter, map, mapTo, switchMap, take } from 'rxjs/operators';
import { createSignalsFactory } from './signals-factory';

@@ -28,3 +28,3 @@ import { getIdentifier, NO_VALUE } from './store.utils';

try {
return config.effect(input, store, previousInput, previousResult);
return config.effect(input, store, previousInput, previousResult).pipe(take(1));
}

@@ -81,2 +81,4 @@ catch (error) {

resultInput: input,
previousInput: resultState.resultInput,
previousResult: resultState.result,
},

@@ -118,3 +120,3 @@ })), catchError(error => of({

setup,
signals: (config.withTrigger ? ids : withoutTriggerID),
ids: (config.withTrigger ? ids : withoutTriggerID),
};

@@ -121,0 +123,0 @@ };

export { CombinedEffectResult, EffectError, EffectSignalsFactory, EffectSignalsType, EffectSuccess, EffectType, getEffectSignalsFactory, TriggeredEffectSignalsType, } from './effect-signals-factory';
export { createSignalsFactory, MappedSignalsType, Signals, SignalsFactory, signalsFactoryBind, signalsFactoryMap, } from './signals-factory';
export { Store, TypedEvent } from './store';
export { createSignalsFactory, FactoryBind, FactoryBuild, FactoryFlattenIds as FactoryFlattenComposedIds, FactoryIdsMap, FactoryMap, FlattenComposedIds, IdsMapper, MappedSignalTypes, SetupWithStore, SignalIds, Signals, SignalsFactory, SignalsMapper, SignalsMapToFactory, SignalTypes, } from './signals-factory';
export { StateReducer, Store, TypedEvent } from './store';
export { getIdentifier, NO_VALUE, TypeIdentifier } from './store.utils';
export { getValidatedInputWithResultSignalsFactory, ValidatedInputWithResult, ValidatedInputWithResultSignalsFactory, ValidatedInputWithResultSignalsType, ValidatedInputWithTriggeredResultSignalsType, } from './validated-input-with-result-signals-factory';
export { getEffectSignalsFactory, } from './effect-signals-factory';
export { createSignalsFactory, signalsFactoryBind, signalsFactoryMap, } from './signals-factory';
export { createSignalsFactory, } from './signals-factory';
export { Store } from './store';

@@ -4,0 +4,0 @@ export { getIdentifier, NO_VALUE } from './store.utils';

import { Store } from './store';
declare type SetupWithStore = {
import { TypeIdentifier } from './store.utils';
/**
* This type defines an object that maps identifier names on type identifiers.
*
* @typedef {object} SignalIds - maps strings on TypeIdentifier<any> | SignalIds
*/
export declare type SignalIds = Readonly<{
[key: string]: TypeIdentifier<any> | SignalIds;
}>;
/**
* This type defines an object with a function 'setup' that takes a store instance
* as argument and executes the required setup to produce certain signals.
*
* @typedef {object} SetupWithStore - has a function setup(store) => void
*/
export declare type SetupWithStore = {
readonly setup: (store: Store) => void;
};
declare type SignalsTypeWrapper<SignalsType> = {
readonly signals: SignalsType;
/**
* This type defines a wrapper object that has a field 'ids' mapping to a SignalIds object.
*
* @typedef {object} SignalTypes<T extends SignalIds> - wrapper for a SignalsIds object
* @template T - a concrete SignalIds type, specifying the signal identifiers (so an object with TypeIdentifier<T> as values)
*/
export declare type SignalTypes<T extends SignalIds> = {
readonly ids: T;
};
export declare type Signals<SignalsType> = SetupWithStore & SignalsTypeWrapper<SignalsType>;
export declare type MappedSignalsType<SignalsType1, SignalsType2> = Readonly<{
signals1: SignalsType1;
signals2: SignalsType2;
}>;
/**
* This is the interface for signal factories, which represent a higher abstraction over the usage
* of pure behavior and event composition, to encapsulate common patterns of such composition.
* The interface defines a monadic structure, to allow for simple composition of signal factories.
* Use the createSignalsFactory utility function to create your own SignalsFactory (see the implementation
* of EffectSignalsFactory for an example).
* In contrast to SignalTypes, this type defines a wrapper object that has two fields 'ids1'
* and 'ids2' mapping to SignalIds objects. It is the default SignalTypes object of a
* SignalsFactory resulting from a SignalsFactory.bind().
* So 'ids1' is the SignalsTypes object of the first SignalsFactory and 'ids2' is the
* SignalsTypes of the bound SignalsFactory.
*
* @typedef {object} SignalsFactory<SignalsType> - type for monadic signal factories
* @template SignalsType - specifies the type for signals provided by the factory (type identifiers)
* @property {function} build - returns an object with a setup function (taking a store as argument) and the signals being setup
* @property {function} bind - the monadic bind (aka flatMap) to compose with other signal factories
* @property {function} fmap - (aka map) the functor map, to map the signals produced by the factory
* @typedef {object} MappedSignalTypes<T1 extends SignalIds, T2 extends SignalIds> - wrapper for signal types of a SignalsFactory resulting from a bind()
* @template T1 - a concrete SignalIds type, specifying the signal identifiers of the initial SignalsFactory
* @template T2 - a concrete SignalIds type, specifying the signal identifiers of the SignalsFactory that was used as argument to SignalsFactory.bind()
*/
export declare type SignalsFactory<SignalsType> = Readonly<{
build: () => Signals<SignalsType>;
bind: <SignalsType2>(mapper: (signals: Signals<SignalsType>) => SignalsFactory<SignalsType2>) => SignalsFactory<MappedSignalsType<SignalsType, SignalsType2>>;
fmap: <SignalsType2>(mapper: (signals: Signals<SignalsType>) => Signals<SignalsType2>) => SignalsFactory<SignalsType2>;
export declare type MappedSignalTypes<T1 extends SignalIds, T2 extends SignalIds> = Readonly<{
ids1: T1;
ids2: T2;
}>;
declare type SignalsFactoryMapCreate = <SignalsType1, SignalsType2>(factory1: SignalsFactory<SignalsType1>, mapper: (signals: Signals<SignalsType1>) => Signals<SignalsType2>) => SignalsFactory<SignalsType2>;
/**
* A utility function that implements fmap for signal factories. However, instead of using this
* low-level function, in most cases you should just use the createSignalsFactory utility function.
* This type defines an object that encapsulates SignalIds and a function that takes a store
* and performs the setup of all the corresponding signals.
*
* @template SignalsType1 - specifies the signals type for the input factory
* @template SignalsType2 - specifies the signals type for the resulting factory
* @param {SignalsFactory<SignalsType1>} factory1 - the input factory
* @param {function} mapper - the function mapping from Signals<SignalsType1> to Signals<SignalsType2>
* @returns {SignalsFactory<SignalsType2>} the resulting factory
* @typedef {object} Signals<T> - composition of SetupWithStore and SignalTypes<T>
* @template T - a concrete SignalIds type
*/
export declare const signalsFactoryMap: SignalsFactoryMapCreate;
declare type SignalsFactoryBindCreate = <SignalsType1, SignalsType2>(factory1: SignalsFactory<SignalsType1>, mapper: (signals: Signals<SignalsType1>) => SignalsFactory<SignalsType2>) => SignalsFactory<MappedSignalsType<SignalsType1, SignalsType2>>;
export declare type Signals<T extends SignalIds> = SetupWithStore & SignalTypes<T>;
/**
* A utility function that implements bind for signal factories. However, instead of using this
* low-level function, in most cases you should just use the createSignalsFactory utility function.
* This type specifies a function mapping from Signals<T1> to SignalsFactory<T2>, hence
* the argument to the monadic bind of SignalFactories (hence the argument to FactoryBind<T1,T2>).
*
* @template SignalsType1 - specifies the signals type for the input factory
* @template SignalsType2 - specifies the signals type for the resulting factory
* @param {SignalsFactory<SignalsType1>} factory1 - the input factory
* @param {function} mapper - the function mapping from Signals<SignalsType1> to SignalsFactory<SignalsType2>
* @returns {SignalsFactory<SignalsType2>} the resulting factory
* @typedef {function} SignalsMapToFactory<T1 extends SignalIds, T2 extends SignalIds> - function mapping from Signals<T1> to SignalsFactory<T2>
* @template T1 - the concrete SignalIds type of the initial SignalsFactory
* @template T2 - the concrete SignalIds type of the resulting SignalsFactory
*/
export declare const signalsFactoryBind: SignalsFactoryBindCreate;
declare type SignalsFactoryCreate = <SignalsType>(build: () => Signals<SignalsType>) => SignalsFactory<SignalsType>;
export declare type SignalsMapToFactory<T1 extends SignalIds, T2 extends SignalIds> = (signals: Signals<T1>) => SignalsFactory<T2>;
/**
* This utility function creates an object that implements the SignalsFactory interface. It should be
* This type specifies a function mapping from Signals<T1> to Signals<T2>, hence
* the argument to the functor fmap of SignalFactories (hence the argument to FactoryMap<T1,T2>).
*
* @typedef {function} SignalsMapper<T1 extends SignalIds, T2 extends SignalIds> - function mapping from Signals<T1> to Signals<T2>
* @template T1 - the concrete SignalIds type of the initial SignalsFactory
* @template T2 - the concrete SignalIds type of the resulting SignalsFactory
*/
export declare type SignalsMapper<T1 extends SignalIds, T2 extends SignalIds> = (signals: Signals<T1>) => Signals<T2>;
/**
* This type specifies a function mapping from SignalIds T1 to SignalIds T2.
*
* @typedef {function} IdsMapper<T1 extends SignalIds, T2 extends SignalIds> - function mapping from T1 to T2
* @template T1 - the concrete SignalIds type of the initial SignalsFactory
* @template T2 - the concrete SignalIds type of the resulting SignalsFactory
*/
export declare type IdsMapper<T1 extends SignalIds, T2 extends SignalIds> = (ids: T1) => T2;
/**
* This type defines a function returning a Signals object, hence a function implementing SignalsFactory.build().
*
* @typedef {function} FactoryBuild<SignalsType> - type for the build method of SignalsFactories
* @template T - the concrete SignalIds type of the resulting Signals
*/
export declare type FactoryBuild<T extends SignalIds> = () => Signals<T>;
/**
* This type defines a function implementing the monadic bind for SignalsFactory<SignalsType>.
*
* @typedef {function} FactoryBind<T1> - type for the bind method of SignalsFactories
* @template T1 - the concrete SignalIds provided by the implementing SignalsFactory
* @template T2 - the concrete SignalIds provided by the SignalsFactory being the argument to the bind
* @property {SignalsMapToFactory<T1, T2>} mapper
*/
export declare type FactoryBind<T1 extends SignalIds> = <T2 extends SignalIds>(mapper: SignalsMapToFactory<T1, T2>) => SignalsFactory<MappedSignalTypes<T1, T2>>;
/**
* This type defines a function making SignalsFactory a functor.
*
* @typedef {function} FactoryMap<T1> - type for the fmap method of SignalsFactories
* @template T1 - the concrete SignalIds provided by the implementing SignalsFactory
* @template T2 - the concrete SignalIds provided by the resulting SignalsFactory
* @property {SignalsMapper<T1, T2>} mapper
*/
export declare type FactoryMap<T1 extends SignalIds> = <T2 extends SignalIds>(mapper: SignalsMapper<T1, T2>) => SignalsFactory<T2>;
/**
* This type defines a function mapping from one SignalsFactory to a new SignalsFactory that works
* like the original one, just that the SignalsIds object is changed (e.g. renamed identifiers
* or less identifiers being exposed, etc.).
*
* @typedef {function} FactoryIdsMap<T1> - type for the idsMap method of SignalsFactories
* @template T1 - the concrete SignalIds provided by the implementing SignalsFactory
* @template T2 - the concrete SignalIds provided by the resulting SignalsFactory
* @property {IdsMapper<T1, T2>} mapper
*/
export declare type FactoryIdsMap<T1 extends SignalIds> = <T2 extends SignalIds>(mapper: IdsMapper<T1, T2>) => SignalsFactory<T2>;
/**
* This type defines a function mapping from a composed SignalsFactory<T>
* to a SignalsFactory<FlattenComposedIds<T>>.
* If T is MappedSignalTypes<T1, T2>, then the new Ids will be flattened,
* else the Ids type will just not be changed.
*
* @typedef {function} FactoryFlattenIds<T> - type for the flattenIds method of SignalsFactories
* @template T - the concrete SignalIds provided by the implementing SignalsFactory
*/
export declare type FactoryFlattenIds<T extends SignalIds> = () => SignalsFactory<FlattenComposedIds<T>>;
/**
* This is the type for signal factories, which represent a higher abstraction over the usage
* of pure behavior and event composition, to encapsulate common patterns of such composition.
* It defines a monadic structure, to allow for simple composition of signal factories.
* Use the createSignalsFactory utility function to create your own SignalsFactories
* (see the implementation of EffectSignalsFactory for an example).
*
* @typedef {object} SignalsFactory<T>
* @template T - the concrete SignalIds provided by the factory
* @property {FactoryBuild<T>} build - returns Signals<T>, so an object with a setup function (taking a store as argument) and the signals being setup
* @property {FactoryBind<T>} bind - the monadic bind (aka flatMap) to compose with other signal factories
* @property {FactoryMap<T>} fmap - (aka map) the functor map, to map the Signals<T> produced by the factory to different Signals<T2>
* @property {FactoryIdsMap<T>} idsMap - to map the T to a T2
* @property {FactoryFlattenIds<T>} flattenIds - to map the T to FlattenComposedIds<T> (due to current TS-limitations, you must call this multiple times to also flatten nested MappedSignalTypes)
*/
export declare type SignalsFactory<T extends SignalIds> = Readonly<{
build: FactoryBuild<T>;
bind: FactoryBind<T>;
fmap: FactoryMap<T>;
idsMap: FactoryIdsMap<T>;
flattenIds: FactoryFlattenIds<T>;
}>;
declare type NoConflictKeys1<Parent, Child> = {
[CK in keyof Child]: CK extends keyof Parent ? never : CK;
}[keyof Child];
declare type ConflictKeys1<Parent, Child> = {
[CK in keyof Child]: CK extends keyof Parent ? CK : never;
}[string & keyof Child];
declare type NoConflict1<Parent, Child> = {
[CK in NoConflictKeys1<Parent, Child>]: Child[CK];
};
declare type Conflict1<Parent, Child> = {
[CK in ConflictKeys1<Parent, Child> as `${CK}_1`]: Child[CK];
};
declare type MappedChild1<Parent extends SignalIds, Child extends SignalIds> = NoConflict1<Parent, Child> & Conflict1<Parent, Child>;
declare type NoConflictKeys2<Parent, Ids1Child, Child> = {
[CK in keyof Child]: CK extends keyof Parent | keyof Ids1Child ? never : CK;
}[keyof Child];
declare type ConflictKeys2<Parent, Ids1Child, Child> = {
[CK in keyof Child]: CK extends keyof Parent | keyof Ids1Child ? CK : never;
}[string & keyof Child];
declare type NoConflict2<Parent, Ids1Child, Child> = {
[CK in NoConflictKeys2<Parent, Ids1Child, Child>]: Child[CK];
};
declare type Conflict2<Parent, Ids1Child, Child> = {
[CK in ConflictKeys2<Parent, Ids1Child, Child> as `${CK}_2`]: Child[CK];
};
declare type MappedChild2<Parent extends SignalIds, Ids1Child, Child> = NoConflict2<Parent, Ids1Child, Child> & Conflict2<Parent, Ids1Child, Child>;
declare type Ids1Flat<T extends SignalIds> = T extends {
ids1: SignalIds;
} ? MappedChild1<Omit<T, 'ids1' | 'ids2'>, T['ids1']> : {};
declare type Ids2Flat<T extends SignalIds> = T extends {
ids1: SignalIds;
ids2: SignalIds;
} ? MappedChild2<Omit<T, 'ids1' | 'ids2'>, T['ids1'], T['ids2']> : {};
/**
* When binding two SignalsFactories with SignalIds T1 and T2, the resulting SignalIds are of
* type MappedSignalTypes<T1, T2>.
* The FlattenComposedIds<T extends SignalIds> type constructor maps T to T in case that T does
* not extend { ids1: SignalIds; ids2: SignalIds }. Otherwise, it will spread the ids1 and ids2
* content (lifting the underlying properties one level up). Conflicting property names will be modified.
* E.g. the following type:
* {
* a: TypeIdentifier<number>;
* ids1: {
* a: TypeIdentifier<string>;
* b: TypeIdentifier<string>;
* };
* ids2: {
* a: TypeIdentifier<boolean>;
* b: TypeIdentifier<boolean>;
* c: TypeIdentifier<boolean>;
* };
* };
* will be mapped to:
* {
* a: TypeIdentifier<number>;
* a_1: TypeIdentifier<string>;
* b: TypeIdentifier<string>;
* a_2: TypeIdentifier<boolean>;
* b_2: TypeIdentifier<boolean>;
* c: TypeIdentifier<boolean>;
* };
* hence, conflicting properties will be appended by '_1' in case they come from 'ids1', or
* by '_2' in case they come from 'ids2'.
*
* @typedef {object} FlattenComposedIds<T extends SignalIds> - flattens (nested) MappedSignalTypes
* @template T - a concrete SignalIds type
*/
export declare type FlattenComposedIds<T extends SignalIds> = Omit<T, 'ids1' | 'ids2'> & Ids1Flat<T> & Ids2Flat<T>;
declare type SignalsFactoryCreate = <T extends SignalIds>(build: () => Signals<T>) => SignalsFactory<T>;
/**
* This utility function creates an object that implements the SignalsFactory type. It should be
* used to implement all specific signal factories (by just extending the returned object as required).
* See the implementation of EffectSignalsFactory (which is actually a builder) for an example.
*
* @template SignalsType - specifies the signals type for the factory
* @param {function} build - the function that implements build for SignalsFactory<SignalsType>
* @returns {SignalsFactory<SignalsType>}
* @template T - the concrete SignalIds type type for the factory
* @param {FactoryBuild<T>} build - the function that implements build for SignalsFactory<T>
* @returns {SignalsFactory<T>}
*/
export declare const createSignalsFactory: SignalsFactoryCreate;
export {};

@@ -1,36 +0,70 @@

/* eslint-disable @typescript-eslint/no-use-before-define */
/**
* A utility function that implements fmap for signal factories. However, instead of using this
* low-level function, in most cases you should just use the createSignalsFactory utility function.
*
* @template SignalsType1 - specifies the signals type for the input factory
* @template SignalsType2 - specifies the signals type for the resulting factory
* @param {SignalsFactory<SignalsType1>} factory1 - the input factory
* @param {function} mapper - the function mapping from Signals<SignalsType1> to Signals<SignalsType2>
* @returns {SignalsFactory<SignalsType2>} the resulting factory
*/
export const signalsFactoryMap = (factory1, mapper) => {
const newBuild = () => mapper(factory1.build());
const signalsFactoryFlattenComposedIds = (factory) => signalsFactoryIdsMap(factory, (ids) => flattenSignalIds(ids));
const signalsFactoryIdsMap = (factory1, mapper) => {
const fmapper = s => ({
ids: mapper(s.ids),
setup: s.setup,
});
const build = () => fmapper(factory1.build());
let factory2;
const newMap = (mapper2) => signalsFactoryMap(factory2, mapper2);
const newBind = (mapper2) => signalsFactoryBind(factory2, mapper2);
const fmap = (mapper2) => signalsFactoryMap(factory2, mapper2);
const idsMap = (mapper2) => signalsFactoryIdsMap(factory2, mapper2);
const bind = (mapper2) => signalsFactoryBind(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build: newBuild,
bind: newBind,
fmap: newMap,
build,
bind,
fmap,
idsMap,
flattenIds,
};
return factory2;
};
/**
* A utility function that implements bind for signal factories. However, instead of using this
* low-level function, in most cases you should just use the createSignalsFactory utility function.
*
* @template SignalsType1 - specifies the signals type for the input factory
* @template SignalsType2 - specifies the signals type for the resulting factory
* @param {SignalsFactory<SignalsType1>} factory1 - the input factory
* @param {function} mapper - the function mapping from Signals<SignalsType1> to SignalsFactory<SignalsType2>
* @returns {SignalsFactory<SignalsType2>} the resulting factory
*/
export const signalsFactoryBind = (factory1, mapper) => {
const newBuild = () => {
const signalsFactoryMap = (factory1, mapper) => {
const build = () => mapper(factory1.build());
let factory2;
const fmap = (mapper2) => signalsFactoryMap(factory2, mapper2);
const idsMap = (mapper2) => signalsFactoryIdsMap(factory2, mapper2);
const bind = (mapper2) => signalsFactoryBind(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build,
bind,
fmap,
idsMap,
flattenIds,
};
return factory2;
};
const flattenIdsImpl = (ids) => {
if (ids.ids1 && ids.ids2) {
const result = Object.assign({}, ids);
const { ids1, ids2 } = result;
delete result.ids1;
delete result.ids2;
Object.entries(ids1).forEach(([k, v]) => {
let kNew = k;
while (result[kNew]) {
kNew += '_1';
}
result[kNew] = v;
});
Object.entries(ids2).forEach(([k, v]) => {
let kNew = k;
while (result[kNew]) {
kNew += '_2';
}
result[kNew] = v;
});
// A recursive implementation is trivial, but calculating its corresponding result
// type recursilvely, as of TS 4.4.4, results in:
// 'Type instantiation is excessively deep and possibly infinite.ts(2589)'
// Maybe future TS versions can handle complex type definitions more efficiently
// return flattenIdsImpl(result);
return result;
}
return ids;
};
const flattenSignalIds = (ids) => flattenIdsImpl(ids);
const signalsFactoryBind = (factory1, mapper) => {
const build = () => {
const s1 = factory1.build();

@@ -44,5 +78,5 @@ const factory2 = mapper(s1);

},
signals: {
signals1: s1.signals,
signals2: s2.signals,
ids: {
ids1: s1.ids,
ids2: s2.ids,
},

@@ -52,8 +86,12 @@ };

let factory2;
const newBind = (mapper2) => signalsFactoryBind(factory2, mapper2);
const newMap = (mapper2) => signalsFactoryMap(factory2, mapper2);
const bind = (mapper2) => signalsFactoryBind(factory2, mapper2);
const fmap = (mapper2) => signalsFactoryMap(factory2, mapper2);
const idsMap = (mapper2) => signalsFactoryIdsMap(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build: newBuild,
bind: newBind,
fmap: newMap,
build,
bind,
fmap,
idsMap,
flattenIds,
};

@@ -63,9 +101,9 @@ return factory2;

/**
* This utility function creates an object that implements the SignalsFactory interface. It should be
* This utility function creates an object that implements the SignalsFactory type. It should be
* used to implement all specific signal factories (by just extending the returned object as required).
* See the implementation of EffectSignalsFactory (which is actually a builder) for an example.
*
* @template SignalsType - specifies the signals type for the factory
* @param {function} build - the function that implements build for SignalsFactory<SignalsType>
* @returns {SignalsFactory<SignalsType>}
* @template T - the concrete SignalIds type type for the factory
* @param {FactoryBuild<T>} build - the function that implements build for SignalsFactory<T>
* @returns {SignalsFactory<T>}
*/

@@ -76,2 +114,4 @@ export const createSignalsFactory = (build) => {

const fmap = (mapper) => signalsFactoryMap(factory, mapper);
const idsMap = (mapper) => signalsFactoryIdsMap(factory, mapper);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory);
factory = {

@@ -81,2 +121,4 @@ build,

fmap,
idsMap,
flattenIds,
};

@@ -83,0 +125,0 @@ return factory;

@@ -74,3 +74,3 @@ import { Observable } from 'rxjs';

* @param {Observable<T>} observable - the source for the behavior
* @param {boolean} subscribeLazy - set this to false, if the behavior should always be subscribed (the Store will subscribe it in that case)
* @param {boolean} subscribeLazy - set this to false, if the behavior should always be subscribed (the Store will subscribe it in that case, immediately turning it into a hot observable)
* @param {T | (() => T) | symbol} initialValueOrValueGetter - the initial value or value getter (for lazy initialization) or symbol NO_VALUE, if there is no initial value (default)

@@ -108,5 +108,5 @@ * @returns {void}

/**
* This adds a reducer to a bahavior. This is meant to be used together with the addState method.
* This adds a reducer to a behavior. This is meant to be used together with the addState method.
* Technically, you can also add reducers to behaviors that were added with one of the addBevavior methods.
* However, this is strongly discouraged and might result in unexpected (literally) behavior.
* However, this is strongly discouraged and might result in unexpected behavior (literally).
*

@@ -113,0 +113,0 @@ * @param {TypeIdentifier<T>} stateIdentifier - the unique identifier for the behavior

@@ -68,3 +68,3 @@ import { asyncScheduler, BehaviorSubject, combineLatest, merge, NEVER, of } from 'rxjs';

* @param {Observable<T>} observable - the source for the behavior
* @param {boolean} subscribeLazy - set this to false, if the behavior should always be subscribed (the Store will subscribe it in that case)
* @param {boolean} subscribeLazy - set this to false, if the behavior should always be subscribed (the Store will subscribe it in that case, immediately turning it into a hot observable)
* @param {T | (() => T) | symbol} initialValueOrValueGetter - the initial value or value getter (for lazy initialization) or symbol NO_VALUE, if there is no initial value (default)

@@ -112,5 +112,5 @@ * @returns {void}

/**
* This adds a reducer to a bahavior. This is meant to be used together with the addState method.
* This adds a reducer to a behavior. This is meant to be used together with the addState method.
* Technically, you can also add reducers to behaviors that were added with one of the addBevavior methods.
* However, this is strongly discouraged and might result in unexpected (literally) behavior.
* However, this is strongly discouraged and might result in unexpected behavior (literally).
*

@@ -126,2 +126,8 @@ * @param {TypeIdentifier<T>} stateIdentifier - the unique identifier for the behavior

}
// connectBehaviorIds<T>(
// sourceIdentifier: TypeIdentifier<T>,
// targetIdentifier: TypeIdentifier<T>,
// ): void {
// this.addLazyBehavior(targetIdentifier, this.getBehavior(sourceIdentifier));
// }
/**

@@ -128,0 +134,0 @@ * This method can be used to remove a reducer from a behavior.

import { Observable } from 'rxjs';
import { EffectError, EffectSuccess, EffectType } from './effect-signals-factory';
import { SignalsFactory } from './signals-factory';
import { SignalIds, SignalsFactory } from './signals-factory';
import { Store } from './store';

@@ -28,6 +28,6 @@ import { TypeIdentifier } from './store.utils';

};
export declare type ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, SignalsType> = SignalsFactory<SignalsType> & {
export declare type ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, T extends SignalIds> = SignalsFactory<T> & {
withTrigger: () => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, ValidatedInputWithTriggeredResultSignalsType<InputType, ValidationType, ResultType>>;
withInitialResult: (resultGetter?: () => ResultType) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, SignalsType>;
withCustomResultEffectInputEquals: (resultEffectInputEquals: (a: InputType, b: InputType) => boolean) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, SignalsType>;
withInitialResult: (resultGetter?: () => ResultType) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, T>;
withCustomResultEffectInputEquals: (resultEffectInputEquals: (a: InputType, b: InputType) => boolean) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, T>;
};

@@ -52,2 +52,4 @@ export declare const getValidatedInputWithResultSignalsFactory: <InputType, ValidationType, ResultType>(inputGetter: (store: Store) => Observable<InputType>, validationEffect: EffectType<InputType, ValidationType>, isValidationResultValid: (validationResult: ValidationType) => boolean, resultEffect: EffectType<InputType, ResultType>) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, Readonly<{

resultInput: InputType;
previousInput?: InputType | undefined;
previousResult?: ValidationType | undefined;
}>>;

@@ -62,4 +64,6 @@ validationInvalidateEvent: TypeIdentifier<void>;

resultInput: InputType;
previousInput?: InputType | undefined;
previousResult?: ResultType | undefined;
}>>;
resultInvalidateEvent: TypeIdentifier<void>;
}>>;

@@ -20,4 +20,4 @@ import { combineLatest } from 'rxjs';

store.addLazyBehavior(id, combineLatest([
store.getBehavior(signals.signals.signals1.combinedBehavior),
store.getBehavior(signals.signals.signals2.combinedBehavior).pipe(startWith({
store.getBehavior(signals.ids.ids1.combinedBehavior),
store.getBehavior(signals.ids.ids2.combinedBehavior).pipe(startWith({
currentInput: undefined,

@@ -43,3 +43,3 @@ resultInput: undefined,

const factory = validationFactory
.bind(validationSignals => getEffectSignalsFactory((store) => resultInputGetter(store, validationSignals.signals.combinedBehavior, config.isValidationResultValid), config.resultEffect)
.bind(validationSignals => getEffectSignalsFactory((store) => resultInputGetter(store, validationSignals.ids.combinedBehavior, config.isValidationResultValid), config.resultEffect)
.withTrigger()

@@ -53,11 +53,11 @@ .withInitialResult(config.initialResultGetter)

setup,
signals: {
ids: {
combinedBehavior,
validationErrorEvents: signals.signals.signals1.errorEvents,
validationSuccessEvents: signals.signals.signals1.successEvents,
validationInvalidateEvent: signals.signals.signals1.invalidateEvent,
resultErrorEvents: signals.signals.signals2.errorEvents,
resultSuccessEvents: signals.signals.signals2.successEvents,
resultInvalidateEvent: signals.signals.signals2.invalidateEvent,
resultTriggerEvent: signals.signals.signals2.triggerEvent,
validationErrorEvents: signals.ids.ids1.errorEvents,
validationSuccessEvents: signals.ids.ids1.successEvents,
validationInvalidateEvent: signals.ids.ids1.invalidateEvent,
resultErrorEvents: signals.ids.ids2.errorEvents,
resultSuccessEvents: signals.ids.ids2.successEvents,
resultInvalidateEvent: signals.ids.ids2.invalidateEvent,
resultTriggerEvent: signals.ids.ids2.triggerEvent,
},

@@ -71,3 +71,3 @@ };

const factory = validationFactory
.bind(validationSignals => getEffectSignalsFactory((store) => resultInputGetter(store, validationSignals.signals.combinedBehavior, config.isValidationResultValid), config.resultEffect)
.bind(validationSignals => getEffectSignalsFactory((store) => resultInputGetter(store, validationSignals.ids.combinedBehavior, config.isValidationResultValid), config.resultEffect)
.withInitialResult(config.initialResultGetter)

@@ -80,10 +80,10 @@ .withCustomEffectInputEquals(config.resultEffectInputEquals))

setup,
signals: {
ids: {
combinedBehavior,
validationErrorEvents: signals.signals.signals1.errorEvents,
validationSuccessEvents: signals.signals.signals1.successEvents,
validationInvalidateEvent: signals.signals.signals1.invalidateEvent,
resultErrorEvents: signals.signals.signals2.errorEvents,
resultSuccessEvents: signals.signals.signals2.successEvents,
resultInvalidateEvent: signals.signals.signals2.invalidateEvent,
validationErrorEvents: signals.ids.ids1.errorEvents,
validationSuccessEvents: signals.ids.ids1.successEvents,
validationInvalidateEvent: signals.ids.ids1.invalidateEvent,
resultErrorEvents: signals.ids.ids2.errorEvents,
resultSuccessEvents: signals.ids.ids2.successEvents,
resultInvalidateEvent: signals.ids.ids2.invalidateEvent,
},

@@ -90,0 +90,0 @@ };

{
"name": "@rx-signals/store",
"version": "2.7.0-rc1",
"version": "2.7.0-rc2",
"description": "Reactive effects management with behaviors and event streams",

@@ -20,3 +20,4 @@ "author": "Gerd Neudert",

"lint": "eslint --ext .ts \"src/**\"",
"pre-publish": "rm -rf dist && npm run format && npm run lint && npm run test && npm run build"
"generate-docs": "typedoc --out docs/tsdoc src",
"pre-publish": "rm -rf dist && rm -rf docs/tsdoc && rm -rf coverage && npm run format && npm run lint && npm run test && npm run build && npm run generate-docs"
},

@@ -49,11 +50,10 @@ "keywords": [

"devDependencies": {
"rxjs": "^7.3.0",
"@types/jest": "^26.0.24",
"@typescript-eslint/eslint-plugin": "^4.31.2",
"@typescript-eslint/parser": "^4.31.2",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"eslint": "^7.32.0",
"eslint-config-airbnb-typescript": "^12.3.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^24.4.2",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jest": "^24.7.0",
"eslint-plugin-jsx-a11y": "^6.4.1",

@@ -63,5 +63,7 @@ "eslint-plugin-prettier": "^3.4.1",

"prettier": "^2.4.1",
"rxjs": "^7.4.0",
"ts-jest": "^26.5.6",
"typescript": "^4.3.5"
"typedoc": "^0.22.8",
"typescript": "^4.4.4"
}
}

@@ -1,9 +0,107 @@

# @rx-signals/store
# _@rx-signals/store_
**Reactive effects management with behaviors and event streams**
**Reactive state and effects management**
Yes, I published the first initial release and there is still no documentation
## Installation
But there will be in the near future...
`npm install --save @rx-signals/store`
(At leat the store API meanwhile has some doc strings)
## Dependencies
**_RxJs_** is the one and only peer dependency. You need a version >6.4.0 (so 7.x is also perfectly fine) in your project.
## License
[MIT](https://choosealicense.com/licenses/mit/)
## What is it?
_rx-signals_ is a library for the MVU (**M**odel-**V**iew-**U**pdate) pattern.
It is however not limited to MVU, but can be used in all architectures that would benefit from its features:
* State Management
* Global and/or local
* Reactive Programming
* High-level abstractions over _RxJs_ (you can still go as low as you want)
* Effects Management
* Clean side-effect isolation
* Mock-less testing of your application logic
* An alternative to _Redux_, _NgRx_ or other MVU-libs
* Less boilerplate / More DRY
* More abstractions / reusability
Though it heavily relies on _RxJs_, this lib is **not** Angular-specific. You can (and should) also use it in any other context where you have _RxJs_ at your disposal!
_rx-signals_ itself is implemented with TypeScript and therefore naturally comes **fully typed** (in case you're using it with TS).
### High-level overview
This lib comes with a
* Store-API for
* State/Effects-management based on the RP (reactive programming) concepts of events and behaviors (generalized as signals)
* Reactive dependency injection
* Signals-Type as
* Encapsulation/Abstraction-layer for signal-composition
* SignalsFactory-Type and utility functions as
* Abstraction-layer over the Signals-Type for high-level composition and DRY architecture
* EffectSignalsFactory as
* SignalsFactory-implementation that covers side-effect-scenarios, encapsulating and abstracting away all the pitfalls and possibilities to shoot yourself in the foot.
## Getting started
The impatient reader may skip the terminology part and head on to [Directions](#directions).
### Terminology <a name="terminology"></a>
What does _rx-signals_ mean anyway?
Well the _rx_ stands for reactive extensions, so it's the same _rx_ as in _RxJs_.
The term _signals_ is lent from the world of functional reactive programming (FRP), though _rx-signals_ features reactive programming (RP).
You can [skip to the definition of _signals_ in RP](#rp-signals-definition), if you're not really interested in the actual difference between FRP and RP:
In **FRP**, there are two kinds of signals:
* Events:
* Signals of values that occur at discrete points in time
* So functions of time that **may or may not** yield a value
* An event can depend on several conditions (e.g. other signals)
* Behaviors:
* Signals of dynamic values over continuous time
* So functions of time that alwayas yield a value
* A behavior can depend on other behaviors and/or events
The FRP-guys may pardon me for having over-simplified a bit.
If you're interested in an exact definition, [here you can start](http://conal.net/papers/icfp97/) (though the above definition better resembles RT-FRP, so the original paper is really just a start).
We're however not interested in the continuous world of FRP, but instead we're working with programs that change in discrete steps, which brings us to RP (in RP the signals are not functions of time, but only of ordered signals they depend on).
This is really confusing, because actually in RP, we're making use of functional programming **a lot**!
It's just that the term FRP is reserved for the thing where behaviors are real functions of continous time.
Don't worry, if this is confusing or even if you still have no idea what I'm talking about.
At least if you're already familiar with _RxJs_ (which is a RP-library), it's going to become much more clear next.
The FRP-definitions of events and behaviors translate to the following definitions for **RP**:<a name="rp-signals-definition"></a>
* Event-streams:
* Value-streams that have no current value
* Publish values (events) to subscribers at discrete points of time
* Can depend on other event-streams and/or behaviors
* Behaviors:
* Value-Streams that always have a current value (though possibly lazy)
* Current value can change at discrete points in time (published to subscribers)
* Can depend on other behaviors and/or event-streams
So an _RxJs_ example for behaviors would be a _BehaviorSubject_, while an example for event-streams would be _Subjects_.
Thus, in _RxJs_-world you can translate _signal_ as _observable_. (Now that we arrived at _RxJs_ terminology: another difference between FRP and RP is that in RP, a signal can simply end, hence observables can complete.)
### Directions <a name="directions"></a>
You should start with my introduction to [MVU, State Management, Reactive Programming and Effects Management](https://github.com/gneu77/rx-signals/blob/master/docs/rp_state_effects_start.md), if
* you don't know what any of these terms mean
* you like to understand the basis for the _rx-signals_ architecture
* you think State Management is only about having a global state and how to modify it
* you think you're doing RP, just because you're using something like _RxJs_ (no, you're not)
* you think Effects Management is only about managing async processes (like http calls)
* you don't know that all these things are tied together
Otherwise, you may start with [**Using _rx-signals_**](https://github.com/gneu77/rx-signals/blob/master/docs/rx-signals_start.md).
Where necessary, it will still link to the corresponding passages of the formerly mentioned introduction.
The API-documentation (as generated from the doc strings) [can be found here](https://rawcdn.githack.com/gneu77/rx-signals/master/docs/tsdoc/index.html)
An introduction for people with _NgRx_ background [can be found here](https://github.com/gneu77/rx-signals/blob/master/docs/ngrx_compare_start.md)

@@ -1,3 +0,3 @@

import { asyncScheduler, Observable, of, Subject } from 'rxjs';
import { delay, mapTo, mergeMap } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';
import { mapTo, mergeMap } from 'rxjs/operators';

@@ -25,15 +25,13 @@ export class DelayedEventQueue {

private signalNext(): void {
of(null)
.pipe(delay(1, asyncScheduler))
.subscribe(() => {
const queueLength = this.queueArray.length;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < queueLength; ++i) {
this.queueArray[0].next();
this.queueArray.shift();
}
if (this.queueArray.length > 0) {
this.signalNext();
}
});
setTimeout(() => {
const queueLength = this.queueArray.length;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < queueLength; ++i) {
this.queueArray[0].next();
this.queueArray.shift();
}
if (this.queueArray.length > 0) {
this.signalNext();
}
}, 0);
}

@@ -40,0 +38,0 @@ }

import { combineLatest, Observable, of, throwError } from 'rxjs';
import { catchError, debounceTime, filter, map, mapTo, switchMap } from 'rxjs/operators';
import { createSignalsFactory, Signals, SignalsFactory } from './signals-factory';
import { catchError, debounceTime, filter, map, mapTo, switchMap, take } from 'rxjs/operators';
import { createSignalsFactory, SignalIds, Signals, SignalsFactory } from './signals-factory';
import { Store } from './store';

@@ -64,2 +64,4 @@ import { getIdentifier, NO_VALUE, TypeIdentifier } from './store.utils';

* @property {InputType} resultInput - the effect input that lead to the result
* @property {InputType | undefined} previousInput - the input of the previous result, or undefined
* @property {ResultType | undefined} previousResult - the previous result, or undefined
*/

@@ -69,2 +71,4 @@ export type EffectSuccess<InputType, ResultType> = Readonly<{

resultInput: InputType;
previousInput?: InputType;
previousResult?: ResultType;
}>;

@@ -125,11 +129,11 @@

type FactoryBuild<SignalsType, ConfigurationType> = (
type FactoryBuilder<T extends SignalIds, ConfigurationType> = (
configuration: ConfigurationType,
) => Signals<SignalsType>;
) => Signals<T>;
const getEffectBuilder = <IT, RT, SignalsType>(): FactoryBuild<
SignalsType,
const getEffectBuilder = <IT, RT, T extends SignalIds>(): FactoryBuilder<
T,
EffectFactoryConfiguration<IT, RT>
> => {
const build: FactoryBuild<SignalsType, EffectFactoryConfiguration<IT, RT>> = (
const build: FactoryBuilder<T, EffectFactoryConfiguration<IT, RT>> = (
config: EffectFactoryConfiguration<IT, RT>,

@@ -144,3 +148,3 @@ ) => {

try {
return config.effect(input, store, previousInput, previousResult);
return config.effect(input, store, previousInput, previousResult).pipe(take(1));
} catch (error) {

@@ -258,2 +262,4 @@ return throwError(error);

resultInput: input,
previousInput: resultState.resultInput,
previousResult: resultState.result,
},

@@ -315,3 +321,3 @@ },

setup,
signals: (config.withTrigger ? ids : withoutTriggerID) as unknown as SignalsType,
ids: (config.withTrigger ? ids : withoutTriggerID) as unknown as T,
};

@@ -347,19 +353,16 @@ };

*/
export type EffectSignalsFactory<InputType, ResultType, SignalsType> =
SignalsFactory<SignalsType> & {
withTrigger: () => EffectSignalsFactory<
InputType,
ResultType,
TriggeredEffectSignalsType<InputType, ResultType>
>;
withInitialResult: (
resultGetter?: () => ResultType,
) => EffectSignalsFactory<InputType, ResultType, SignalsType>;
withEffectDebounce: (
debounceMS: number,
) => EffectSignalsFactory<InputType, ResultType, SignalsType>;
withCustomEffectInputEquals: (
effectInputEquals: (a: InputType, b: InputType) => boolean,
) => EffectSignalsFactory<InputType, ResultType, SignalsType>;
};
export type EffectSignalsFactory<InputType, ResultType, T extends SignalIds> = SignalsFactory<T> & {
withTrigger: () => EffectSignalsFactory<
InputType,
ResultType,
TriggeredEffectSignalsType<InputType, ResultType>
>;
withInitialResult: (
resultGetter?: () => ResultType,
) => EffectSignalsFactory<InputType, ResultType, T>;
withEffectDebounce: (debounceMS: number) => EffectSignalsFactory<InputType, ResultType, T>;
withCustomEffectInputEquals: (
effectInputEquals: (a: InputType, b: InputType) => boolean,
) => EffectSignalsFactory<InputType, ResultType, T>;
};

@@ -369,8 +372,8 @@ const getEffectSignalsFactoryIntern = <

ResultType,
SignalsType extends EffectSignalsType<InputType, ResultType>,
T extends EffectSignalsType<InputType, ResultType>,
>(
config: EffectFactoryConfiguration<InputType, ResultType>,
): EffectSignalsFactory<InputType, ResultType, SignalsType> => {
const builder = getEffectBuilder<InputType, ResultType, SignalsType>();
const build = (): Signals<SignalsType> => builder(config);
): EffectSignalsFactory<InputType, ResultType, T> => {
const builder = getEffectBuilder<InputType, ResultType, T>();
const build = (): Signals<T> => builder(config);
const withTrigger = () =>

@@ -386,3 +389,3 @@ getEffectSignalsFactoryIntern<

const withInitialResult = (resultGetter?: () => ResultType) =>
getEffectSignalsFactoryIntern<InputType, ResultType, SignalsType>({
getEffectSignalsFactoryIntern<InputType, ResultType, T>({
...config,

@@ -392,3 +395,3 @@ initialResultGetter: resultGetter,

const withEffectDebounce = (effectDebounceTime: number) =>
getEffectSignalsFactoryIntern<InputType, ResultType, SignalsType>({
getEffectSignalsFactoryIntern<InputType, ResultType, T>({
...config,

@@ -400,3 +403,3 @@ effectDebounceTime,

) =>
getEffectSignalsFactoryIntern<InputType, ResultType, SignalsType>({
getEffectSignalsFactoryIntern<InputType, ResultType, T>({
...config,

@@ -403,0 +406,0 @@ effectInputEquals,

@@ -13,9 +13,19 @@ export {

createSignalsFactory,
MappedSignalsType,
FactoryBind,
FactoryBuild,
FactoryFlattenIds as FactoryFlattenComposedIds,
FactoryIdsMap,
FactoryMap,
FlattenComposedIds,
IdsMapper,
MappedSignalTypes,
SetupWithStore,
SignalIds,
Signals,
SignalsFactory,
signalsFactoryBind,
signalsFactoryMap,
SignalsMapper,
SignalsMapToFactory,
SignalTypes,
} from './signals-factory';
export { Store, TypedEvent } from './store';
export { StateReducer, Store, TypedEvent } from './store';
export { getIdentifier, NO_VALUE, TypeIdentifier } from './store.utils';

@@ -22,0 +32,0 @@ export {

/* eslint-disable @typescript-eslint/no-use-before-define */
import { Store } from './store';
import { TypeIdentifier } from './store.utils';
type SetupWithStore = {
/**
* This type defines an object that maps identifier names on type identifiers.
*
* @typedef {object} SignalIds - maps strings on TypeIdentifier<any> | SignalIds
*/
export type SignalIds = Readonly<{ [key: string]: TypeIdentifier<any> | SignalIds }>;
/**
* This type defines an object with a function 'setup' that takes a store instance
* as argument and executes the required setup to produce certain signals.
*
* @typedef {object} SetupWithStore - has a function setup(store) => void
*/
export type SetupWithStore = {
readonly setup: (store: Store) => void;
};
type SignalsTypeWrapper<SignalsType> = {
readonly signals: SignalsType;
/**
* This type defines a wrapper object that has a field 'ids' mapping to a SignalIds object.
*
* @typedef {object} SignalTypes<T extends SignalIds> - wrapper for a SignalsIds object
* @template T - a concrete SignalIds type, specifying the signal identifiers (so an object with TypeIdentifier<T> as values)
*/
export type SignalTypes<T extends SignalIds> = {
readonly ids: T;
};
export type Signals<SignalsType> = SetupWithStore & SignalsTypeWrapper<SignalsType>;
export type MappedSignalsType<SignalsType1, SignalsType2> = Readonly<{
signals1: SignalsType1;
signals2: SignalsType2;
/**
* In contrast to SignalTypes, this type defines a wrapper object that has two fields 'ids1'
* and 'ids2' mapping to SignalIds objects. It is the default SignalTypes object of a
* SignalsFactory resulting from a SignalsFactory.bind().
* So 'ids1' is the SignalsTypes object of the first SignalsFactory and 'ids2' is the
* SignalsTypes of the bound SignalsFactory.
*
* @typedef {object} MappedSignalTypes<T1 extends SignalIds, T2 extends SignalIds> - wrapper for signal types of a SignalsFactory resulting from a bind()
* @template T1 - a concrete SignalIds type, specifying the signal identifiers of the initial SignalsFactory
* @template T2 - a concrete SignalIds type, specifying the signal identifiers of the SignalsFactory that was used as argument to SignalsFactory.bind()
*/
export type MappedSignalTypes<T1 extends SignalIds, T2 extends SignalIds> = Readonly<{
ids1: T1;
ids2: T2;
}>;
/**
* This is the interface for signal factories, which represent a higher abstraction over the usage
* of pure behavior and event composition, to encapsulate common patterns of such composition.
* The interface defines a monadic structure, to allow for simple composition of signal factories.
* Use the createSignalsFactory utility function to create your own SignalsFactory (see the implementation
* of EffectSignalsFactory for an example).
* This type defines an object that encapsulates SignalIds and a function that takes a store
* and performs the setup of all the corresponding signals.
*
* @typedef {object} SignalsFactory<SignalsType> - type for monadic signal factories
* @template SignalsType - specifies the type for signals provided by the factory (type identifiers)
* @property {function} build - returns an object with a setup function (taking a store as argument) and the signals being setup
* @property {function} bind - the monadic bind (aka flatMap) to compose with other signal factories
* @property {function} fmap - (aka map) the functor map, to map the signals produced by the factory
* @typedef {object} Signals<T> - composition of SetupWithStore and SignalTypes<T>
* @template T - a concrete SignalIds type
*/
export type SignalsFactory<SignalsType> = Readonly<{
build: () => Signals<SignalsType>;
bind: <SignalsType2>(
mapper: (signals: Signals<SignalsType>) => SignalsFactory<SignalsType2>,
) => SignalsFactory<MappedSignalsType<SignalsType, SignalsType2>>;
fmap: <SignalsType2>(
mapper: (signals: Signals<SignalsType>) => Signals<SignalsType2>,
) => SignalsFactory<SignalsType2>;
}>;
export type Signals<T extends SignalIds> = SetupWithStore & SignalTypes<T>;
type SignalsFactoryMapCreate = <SignalsType1, SignalsType2>(
factory1: SignalsFactory<SignalsType1>,
mapper: (signals: Signals<SignalsType1>) => Signals<SignalsType2>,
) => SignalsFactory<SignalsType2>;
/**
* This type specifies a function mapping from Signals<T1> to SignalsFactory<T2>, hence
* the argument to the monadic bind of SignalFactories (hence the argument to FactoryBind<T1,T2>).
*
* @typedef {function} SignalsMapToFactory<T1 extends SignalIds, T2 extends SignalIds> - function mapping from Signals<T1> to SignalsFactory<T2>
* @template T1 - the concrete SignalIds type of the initial SignalsFactory
* @template T2 - the concrete SignalIds type of the resulting SignalsFactory
*/
export type SignalsMapToFactory<T1 extends SignalIds, T2 extends SignalIds> = (
signals: Signals<T1>,
) => SignalsFactory<T2>;
/**
* A utility function that implements fmap for signal factories. However, instead of using this
* low-level function, in most cases you should just use the createSignalsFactory utility function.
* This type specifies a function mapping from Signals<T1> to Signals<T2>, hence
* the argument to the functor fmap of SignalFactories (hence the argument to FactoryMap<T1,T2>).
*
* @template SignalsType1 - specifies the signals type for the input factory
* @template SignalsType2 - specifies the signals type for the resulting factory
* @param {SignalsFactory<SignalsType1>} factory1 - the input factory
* @param {function} mapper - the function mapping from Signals<SignalsType1> to Signals<SignalsType2>
* @returns {SignalsFactory<SignalsType2>} the resulting factory
* @typedef {function} SignalsMapper<T1 extends SignalIds, T2 extends SignalIds> - function mapping from Signals<T1> to Signals<T2>
* @template T1 - the concrete SignalIds type of the initial SignalsFactory
* @template T2 - the concrete SignalIds type of the resulting SignalsFactory
*/
export const signalsFactoryMap: SignalsFactoryMapCreate = <SignalsType1, SignalsType2>(
factory1: SignalsFactory<SignalsType1>,
mapper: (signals: Signals<SignalsType1>) => Signals<SignalsType2>,
): SignalsFactory<SignalsType2> => {
const newBuild = () => mapper(factory1.build());
let factory2: SignalsFactory<SignalsType2>;
const newMap = <SignalsType3>(
mapper2: (signals: Signals<SignalsType2>) => Signals<SignalsType3>,
): SignalsFactory<SignalsType3> => signalsFactoryMap(factory2, mapper2);
const newBind = <SignalsType3>(
mapper2: (signals: Signals<SignalsType2>) => SignalsFactory<SignalsType3>,
) => signalsFactoryBind(factory2, mapper2);
export type SignalsMapper<T1 extends SignalIds, T2 extends SignalIds> = (
signals: Signals<T1>,
) => Signals<T2>;
/**
* This type specifies a function mapping from SignalIds T1 to SignalIds T2.
*
* @typedef {function} IdsMapper<T1 extends SignalIds, T2 extends SignalIds> - function mapping from T1 to T2
* @template T1 - the concrete SignalIds type of the initial SignalsFactory
* @template T2 - the concrete SignalIds type of the resulting SignalsFactory
*/
export type IdsMapper<T1 extends SignalIds, T2 extends SignalIds> = (ids: T1) => T2;
/**
* This type defines a function returning a Signals object, hence a function implementing SignalsFactory.build().
*
* @typedef {function} FactoryBuild<SignalsType> - type for the build method of SignalsFactories
* @template T - the concrete SignalIds type of the resulting Signals
*/
export type FactoryBuild<T extends SignalIds> = () => Signals<T>;
/**
* This type defines a function implementing the monadic bind for SignalsFactory<SignalsType>.
*
* @typedef {function} FactoryBind<T1> - type for the bind method of SignalsFactories
* @template T1 - the concrete SignalIds provided by the implementing SignalsFactory
* @template T2 - the concrete SignalIds provided by the SignalsFactory being the argument to the bind
* @property {SignalsMapToFactory<T1, T2>} mapper
*/
export type FactoryBind<T1 extends SignalIds> = <T2 extends SignalIds>(
mapper: SignalsMapToFactory<T1, T2>,
) => SignalsFactory<MappedSignalTypes<T1, T2>>;
/**
* This type defines a function making SignalsFactory a functor.
*
* @typedef {function} FactoryMap<T1> - type for the fmap method of SignalsFactories
* @template T1 - the concrete SignalIds provided by the implementing SignalsFactory
* @template T2 - the concrete SignalIds provided by the resulting SignalsFactory
* @property {SignalsMapper<T1, T2>} mapper
*/
export type FactoryMap<T1 extends SignalIds> = <T2 extends SignalIds>(
mapper: SignalsMapper<T1, T2>,
) => SignalsFactory<T2>;
/**
* This type defines a function mapping from one SignalsFactory to a new SignalsFactory that works
* like the original one, just that the SignalsIds object is changed (e.g. renamed identifiers
* or less identifiers being exposed, etc.).
*
* @typedef {function} FactoryIdsMap<T1> - type for the idsMap method of SignalsFactories
* @template T1 - the concrete SignalIds provided by the implementing SignalsFactory
* @template T2 - the concrete SignalIds provided by the resulting SignalsFactory
* @property {IdsMapper<T1, T2>} mapper
*/
export type FactoryIdsMap<T1 extends SignalIds> = <T2 extends SignalIds>(
mapper: IdsMapper<T1, T2>,
) => SignalsFactory<T2>;
/**
* This type defines a function mapping from a composed SignalsFactory<T>
* to a SignalsFactory<FlattenComposedIds<T>>.
* If T is MappedSignalTypes<T1, T2>, then the new Ids will be flattened,
* else the Ids type will just not be changed.
*
* @typedef {function} FactoryFlattenIds<T> - type for the flattenIds method of SignalsFactories
* @template T - the concrete SignalIds provided by the implementing SignalsFactory
*/
export type FactoryFlattenIds<T extends SignalIds> = () => SignalsFactory<FlattenComposedIds<T>>;
/**
* This is the type for signal factories, which represent a higher abstraction over the usage
* of pure behavior and event composition, to encapsulate common patterns of such composition.
* It defines a monadic structure, to allow for simple composition of signal factories.
* Use the createSignalsFactory utility function to create your own SignalsFactories
* (see the implementation of EffectSignalsFactory for an example).
*
* @typedef {object} SignalsFactory<T>
* @template T - the concrete SignalIds provided by the factory
* @property {FactoryBuild<T>} build - returns Signals<T>, so an object with a setup function (taking a store as argument) and the signals being setup
* @property {FactoryBind<T>} bind - the monadic bind (aka flatMap) to compose with other signal factories
* @property {FactoryMap<T>} fmap - (aka map) the functor map, to map the Signals<T> produced by the factory to different Signals<T2>
* @property {FactoryIdsMap<T>} idsMap - to map the T to a T2
* @property {FactoryFlattenIds<T>} flattenIds - to map the T to FlattenComposedIds<T> (due to current TS-limitations, you must call this multiple times to also flatten nested MappedSignalTypes)
*/
export type SignalsFactory<T extends SignalIds> = Readonly<{
build: FactoryBuild<T>;
bind: FactoryBind<T>;
fmap: FactoryMap<T>;
idsMap: FactoryIdsMap<T>;
flattenIds: FactoryFlattenIds<T>;
}>;
type SignalsFactoryMapCreate = <T1 extends SignalIds, T2 extends SignalIds>(
factory1: SignalsFactory<T1>,
mapper: (signals: Signals<T1>) => Signals<T2>,
) => SignalsFactory<T2>;
type SignalsFactoryIdsMapCreate = <T1 extends SignalIds, T2 extends SignalIds>(
factory1: SignalsFactory<T1>,
mapper: (signals: T1) => T2,
) => SignalsFactory<T2>;
type SignalsFactoryFlattenIdsCreate = <T extends SignalIds>(
factory: SignalsFactory<T>,
) => SignalsFactory<FlattenComposedIds<T>>;
const signalsFactoryFlattenComposedIds: SignalsFactoryFlattenIdsCreate = <T extends SignalIds>(
factory: SignalsFactory<T>,
): SignalsFactory<FlattenComposedIds<T>> =>
signalsFactoryIdsMap(factory, (ids: T) => flattenSignalIds(ids));
const signalsFactoryIdsMap: SignalsFactoryIdsMapCreate = <
T1 extends SignalIds,
T2 extends SignalIds,
>(
factory1: SignalsFactory<T1>,
mapper: IdsMapper<T1, T2>,
): SignalsFactory<T2> => {
const fmapper: SignalsMapper<T1, T2> = s => ({
ids: mapper(s.ids),
setup: s.setup,
});
const build = () => fmapper(factory1.build());
let factory2: SignalsFactory<T2>;
const fmap = <T3 extends SignalIds>(mapper2: SignalsMapper<T2, T3>): SignalsFactory<T3> =>
signalsFactoryMap(factory2, mapper2);
const idsMap = <T3 extends SignalIds>(mapper2: IdsMapper<T2, T3>): SignalsFactory<T3> =>
signalsFactoryIdsMap(factory2, mapper2);
const bind = <T3 extends SignalIds>(mapper2: SignalsMapToFactory<T2, T3>) =>
signalsFactoryBind(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build: newBuild,
bind: newBind,
fmap: newMap,
build,
bind,
fmap,
idsMap,
flattenIds,
};

@@ -78,22 +219,151 @@ return factory2;

type SignalsFactoryBindCreate = <SignalsType1, SignalsType2>(
factory1: SignalsFactory<SignalsType1>,
mapper: (signals: Signals<SignalsType1>) => SignalsFactory<SignalsType2>,
) => SignalsFactory<MappedSignalsType<SignalsType1, SignalsType2>>;
const signalsFactoryMap: SignalsFactoryMapCreate = <T1 extends SignalIds, T2 extends SignalIds>(
factory1: SignalsFactory<T1>,
mapper: SignalsMapper<T1, T2>,
): SignalsFactory<T2> => {
const build = () => mapper(factory1.build());
let factory2: SignalsFactory<T2>;
const fmap = <T3 extends SignalIds>(mapper2: SignalsMapper<T2, T3>): SignalsFactory<T3> =>
signalsFactoryMap(factory2, mapper2);
const idsMap = <T3 extends SignalIds>(mapper2: IdsMapper<T2, T3>): SignalsFactory<T3> =>
signalsFactoryIdsMap(factory2, mapper2);
const bind = <T3 extends SignalIds>(mapper2: SignalsMapToFactory<T2, T3>) =>
signalsFactoryBind(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build,
bind,
fmap,
idsMap,
flattenIds,
};
return factory2;
};
// Some helper types for FlattenComposedIds
// This is more like a workaround, because shorter and/or more general and/or recursive
// versions always end up with TypeScript complaining about too complex types.
// (Type instantiation is excessively deep and possibly infinite.ts(2589))
// Maybe in future TypeScript versions, I can come up with something better:
type NoConflictKeys1<Parent, Child> = {
[CK in keyof Child]: CK extends keyof Parent ? never : CK;
}[keyof Child];
type ConflictKeys1<Parent, Child> = {
[CK in keyof Child]: CK extends keyof Parent ? CK : never;
}[string & keyof Child];
type NoConflict1<Parent, Child> = {
[CK in NoConflictKeys1<Parent, Child>]: Child[CK];
};
type Conflict1<Parent, Child> = {
[CK in ConflictKeys1<Parent, Child> as `${CK}_1`]: Child[CK];
};
type MappedChild1<Parent extends SignalIds, Child extends SignalIds> = NoConflict1<Parent, Child> &
Conflict1<Parent, Child>;
type NoConflictKeys2<Parent, Ids1Child, Child> = {
[CK in keyof Child]: CK extends keyof Parent | keyof Ids1Child ? never : CK;
}[keyof Child];
type ConflictKeys2<Parent, Ids1Child, Child> = {
[CK in keyof Child]: CK extends keyof Parent | keyof Ids1Child ? CK : never;
}[string & keyof Child];
type NoConflict2<Parent, Ids1Child, Child> = {
[CK in NoConflictKeys2<Parent, Ids1Child, Child>]: Child[CK];
};
type Conflict2<Parent, Ids1Child, Child> = {
[CK in ConflictKeys2<Parent, Ids1Child, Child> as `${CK}_2`]: Child[CK];
};
type MappedChild2<Parent extends SignalIds, Ids1Child, Child> = NoConflict2<
Parent,
Ids1Child,
Child
> &
Conflict2<Parent, Ids1Child, Child>;
type Ids1Flat<T extends SignalIds> = T extends { ids1: SignalIds }
? MappedChild1<Omit<T, 'ids1' | 'ids2'>, T['ids1']>
: {};
type Ids2Flat<T extends SignalIds> = T extends { ids1: SignalIds; ids2: SignalIds }
? MappedChild2<Omit<T, 'ids1' | 'ids2'>, T['ids1'], T['ids2']>
: {};
/**
* A utility function that implements bind for signal factories. However, instead of using this
* low-level function, in most cases you should just use the createSignalsFactory utility function.
* When binding two SignalsFactories with SignalIds T1 and T2, the resulting SignalIds are of
* type MappedSignalTypes<T1, T2>.
* The FlattenComposedIds<T extends SignalIds> type constructor maps T to T in case that T does
* not extend { ids1: SignalIds; ids2: SignalIds }. Otherwise, it will spread the ids1 and ids2
* content (lifting the underlying properties one level up). Conflicting property names will be modified.
* E.g. the following type:
* {
* a: TypeIdentifier<number>;
* ids1: {
* a: TypeIdentifier<string>;
* b: TypeIdentifier<string>;
* };
* ids2: {
* a: TypeIdentifier<boolean>;
* b: TypeIdentifier<boolean>;
* c: TypeIdentifier<boolean>;
* };
* };
* will be mapped to:
* {
* a: TypeIdentifier<number>;
* a_1: TypeIdentifier<string>;
* b: TypeIdentifier<string>;
* a_2: TypeIdentifier<boolean>;
* b_2: TypeIdentifier<boolean>;
* c: TypeIdentifier<boolean>;
* };
* hence, conflicting properties will be appended by '_1' in case they come from 'ids1', or
* by '_2' in case they come from 'ids2'.
*
* @template SignalsType1 - specifies the signals type for the input factory
* @template SignalsType2 - specifies the signals type for the resulting factory
* @param {SignalsFactory<SignalsType1>} factory1 - the input factory
* @param {function} mapper - the function mapping from Signals<SignalsType1> to SignalsFactory<SignalsType2>
* @returns {SignalsFactory<SignalsType2>} the resulting factory
* @typedef {object} FlattenComposedIds<T extends SignalIds> - flattens (nested) MappedSignalTypes
* @template T - a concrete SignalIds type
*/
export const signalsFactoryBind: SignalsFactoryBindCreate = <SignalsType1, SignalsType2>(
factory1: SignalsFactory<SignalsType1>,
mapper: (signals: Signals<SignalsType1>) => SignalsFactory<SignalsType2>,
): SignalsFactory<MappedSignalsType<SignalsType1, SignalsType2>> => {
const newBuild = () => {
export type FlattenComposedIds<T extends SignalIds> = Omit<T, 'ids1' | 'ids2'> &
Ids1Flat<T> &
Ids2Flat<T>;
type Writeable<T> = { -readonly [P in keyof T]: T[P] };
const flattenIdsImpl = <T extends SignalIds>(ids: T): Writeable<SignalIds> => {
if (ids.ids1 && ids.ids2) {
const result: Writeable<SignalIds> = { ...ids };
const { ids1, ids2 } = result;
delete result.ids1;
delete result.ids2;
Object.entries(ids1).forEach(([k, v]) => {
let kNew = k;
while (result[kNew]) {
kNew += '_1';
}
result[kNew] = v;
});
Object.entries(ids2).forEach(([k, v]) => {
let kNew = k;
while (result[kNew]) {
kNew += '_2';
}
result[kNew] = v;
});
// A recursive implementation is trivial, but calculating its corresponding result
// type recursilvely, as of TS 4.4.4, results in:
// 'Type instantiation is excessively deep and possibly infinite.ts(2589)'
// Maybe future TS versions can handle complex type definitions more efficiently
// return flattenIdsImpl(result);
return result;
}
return ids;
};
const flattenSignalIds = <T extends SignalIds>(ids: T): FlattenComposedIds<T> =>
flattenIdsImpl(ids) as unknown as FlattenComposedIds<T>;
type SignalsFactoryBindCreate = <T1 extends SignalIds, T2 extends SignalIds>(
factory1: SignalsFactory<T1>,
mapper: SignalsMapToFactory<T1, T2>,
) => SignalsFactory<MappedSignalTypes<T1, T2>>;
const signalsFactoryBind: SignalsFactoryBindCreate = <T1 extends SignalIds, T2 extends SignalIds>(
factory1: SignalsFactory<T1>,
mapper: SignalsMapToFactory<T1, T2>,
): SignalsFactory<MappedSignalTypes<T1, T2>> => {
const build = () => {
const s1 = factory1.build();

@@ -107,23 +377,25 @@ const factory2 = mapper(s1);

},
signals: {
signals1: s1.signals,
signals2: s2.signals,
ids: {
ids1: s1.ids,
ids2: s2.ids,
},
};
};
let factory2: SignalsFactory<MappedSignalsType<SignalsType1, SignalsType2>>;
const newBind = <SignalsType3>(
mapper2: (
signals: Signals<MappedSignalsType<SignalsType1, SignalsType2>>,
) => SignalsFactory<SignalsType3>,
let factory2: SignalsFactory<MappedSignalTypes<T1, T2>>;
const bind = <T3 extends SignalIds>(
mapper2: SignalsMapToFactory<MappedSignalTypes<T1, T2>, T3>,
) => signalsFactoryBind(factory2, mapper2);
const newMap = <SignalsType3>(
mapper2: (
signals: Signals<MappedSignalsType<SignalsType1, SignalsType2>>,
) => Signals<SignalsType3>,
): SignalsFactory<SignalsType3> => signalsFactoryMap(factory2, mapper2);
const fmap = <T3 extends SignalIds>(
mapper2: SignalsMapper<MappedSignalTypes<T1, T2>, T3>,
): SignalsFactory<T3> => signalsFactoryMap(factory2, mapper2);
const idsMap = <T3 extends SignalIds>(
mapper2: IdsMapper<MappedSignalTypes<T1, T2>, T3>,
): SignalsFactory<T3> => signalsFactoryIdsMap(factory2, mapper2);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory2);
factory2 = {
build: newBuild,
bind: newBind,
fmap: newMap,
build,
bind,
fmap,
idsMap,
flattenIds,
};

@@ -133,24 +405,24 @@ return factory2;

type SignalsFactoryCreate = <SignalsType>(
build: () => Signals<SignalsType>,
) => SignalsFactory<SignalsType>;
type SignalsFactoryCreate = <T extends SignalIds>(build: () => Signals<T>) => SignalsFactory<T>;
/**
* This utility function creates an object that implements the SignalsFactory interface. It should be
* This utility function creates an object that implements the SignalsFactory type. It should be
* used to implement all specific signal factories (by just extending the returned object as required).
* See the implementation of EffectSignalsFactory (which is actually a builder) for an example.
*
* @template SignalsType - specifies the signals type for the factory
* @param {function} build - the function that implements build for SignalsFactory<SignalsType>
* @returns {SignalsFactory<SignalsType>}
* @template T - the concrete SignalIds type type for the factory
* @param {FactoryBuild<T>} build - the function that implements build for SignalsFactory<T>
* @returns {SignalsFactory<T>}
*/
export const createSignalsFactory: SignalsFactoryCreate = <SignalsType>(
build: () => Signals<SignalsType>,
): SignalsFactory<SignalsType> => {
let factory: SignalsFactory<SignalsType>;
const bind = <SignalsType2>(
mapper: (signals: Signals<SignalsType>) => SignalsFactory<SignalsType2>,
) => signalsFactoryBind(factory, mapper);
const fmap = <SignalsType2>(mapper: (signals: Signals<SignalsType>) => Signals<SignalsType2>) =>
export const createSignalsFactory: SignalsFactoryCreate = <T1 extends SignalIds>(
build: FactoryBuild<T1>,
): SignalsFactory<T1> => {
let factory: SignalsFactory<T1>;
const bind = <T2 extends SignalIds>(mapper: SignalsMapToFactory<T1, T2>) =>
signalsFactoryBind(factory, mapper);
const fmap = <T2 extends SignalIds>(mapper: SignalsMapper<T1, T2>) =>
signalsFactoryMap(factory, mapper);
const idsMap = <T2 extends SignalIds>(mapper: IdsMapper<T1, T2>) =>
signalsFactoryIdsMap(factory, mapper);
const flattenIds = () => signalsFactoryFlattenComposedIds(factory);
factory = {

@@ -160,4 +432,6 @@ build,

fmap,
idsMap,
flattenIds,
};
return factory;
};

@@ -117,3 +117,3 @@ import { asyncScheduler, BehaviorSubject, combineLatest, merge, NEVER, Observable, of } from 'rxjs';

* @param {Observable<T>} observable - the source for the behavior
* @param {boolean} subscribeLazy - set this to false, if the behavior should always be subscribed (the Store will subscribe it in that case)
* @param {boolean} subscribeLazy - set this to false, if the behavior should always be subscribed (the Store will subscribe it in that case, immediately turning it into a hot observable)
* @param {T | (() => T) | symbol} initialValueOrValueGetter - the initial value or value getter (for lazy initialization) or symbol NO_VALUE, if there is no initial value (default)

@@ -182,5 +182,5 @@ * @returns {void}

/**
* This adds a reducer to a bahavior. This is meant to be used together with the addState method.
* This adds a reducer to a behavior. This is meant to be used together with the addState method.
* Technically, you can also add reducers to behaviors that were added with one of the addBevavior methods.
* However, this is strongly discouraged and might result in unexpected (literally) behavior.
* However, this is strongly discouraged and might result in unexpected behavior (literally).
*

@@ -206,2 +206,9 @@ * @param {TypeIdentifier<T>} stateIdentifier - the unique identifier for the behavior

// connectBehaviorIds<T>(
// sourceIdentifier: TypeIdentifier<T>,
// targetIdentifier: TypeIdentifier<T>,
// ): void {
// this.addLazyBehavior(targetIdentifier, this.getBehavior(sourceIdentifier));
// }
/**

@@ -208,0 +215,0 @@ * This method can be used to remove a reducer from a behavior.

@@ -11,3 +11,3 @@ import { combineLatest, Observable } from 'rxjs';

} from './effect-signals-factory';
import { MappedSignalsType, Signals, SignalsFactory } from './signals-factory';
import { MappedSignalTypes, SignalIds, Signals, SignalsFactory } from './signals-factory';
import { Store } from './store';

@@ -46,4 +46,4 @@ import { getIdentifier, TypeIdentifier } from './store.utils';

ResultType,
SignalsType,
> = SignalsFactory<SignalsType> & {
T extends SignalIds,
> = SignalsFactory<T> & {
withTrigger: () => ValidatedInputWithResultSignalsFactory<

@@ -57,6 +57,6 @@ InputType,

resultGetter?: () => ResultType,
) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, SignalsType>;
) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, T>;
withCustomResultEffectInputEquals: (
resultEffectInputEquals: (a: InputType, b: InputType) => boolean,
) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, SignalsType>;
) => ValidatedInputWithResultSignalsFactory<InputType, ValidationType, ResultType, T>;
};

@@ -108,3 +108,3 @@

signals: Signals<
MappedSignalsType<
MappedSignalTypes<
EffectSignalsType<InputType, ValidationType>,

@@ -122,4 +122,4 @@ EffectSignalsType<InputType, ResultType>

combineLatest([
store.getBehavior(signals.signals.signals1.combinedBehavior),
store.getBehavior(signals.signals.signals2.combinedBehavior).pipe(
store.getBehavior(signals.ids.ids1.combinedBehavior),
store.getBehavior(signals.ids.ids2.combinedBehavior).pipe(
startWith({

@@ -178,3 +178,3 @@ currentInput: undefined,

store,
validationSignals.signals.combinedBehavior,
validationSignals.ids.combinedBehavior,
config.isValidationResultValid,

@@ -195,11 +195,11 @@ ),

setup,
signals: {
ids: {
combinedBehavior,
validationErrorEvents: signals.signals.signals1.errorEvents,
validationSuccessEvents: signals.signals.signals1.successEvents,
validationInvalidateEvent: signals.signals.signals1.invalidateEvent,
resultErrorEvents: signals.signals.signals2.errorEvents,
resultSuccessEvents: signals.signals.signals2.successEvents,
resultInvalidateEvent: signals.signals.signals2.invalidateEvent,
resultTriggerEvent: signals.signals.signals2.triggerEvent,
validationErrorEvents: signals.ids.ids1.errorEvents,
validationSuccessEvents: signals.ids.ids1.successEvents,
validationInvalidateEvent: signals.ids.ids1.invalidateEvent,
resultErrorEvents: signals.ids.ids2.errorEvents,
resultSuccessEvents: signals.ids.ids2.successEvents,
resultInvalidateEvent: signals.ids.ids2.invalidateEvent,
resultTriggerEvent: signals.ids.ids2.triggerEvent,
},

@@ -248,3 +248,3 @@ };

store,
validationSignals.signals.combinedBehavior,
validationSignals.ids.combinedBehavior,
config.isValidationResultValid,

@@ -264,10 +264,10 @@ ),

setup,
signals: {
ids: {
combinedBehavior,
validationErrorEvents: signals.signals.signals1.errorEvents,
validationSuccessEvents: signals.signals.signals1.successEvents,
validationInvalidateEvent: signals.signals.signals1.invalidateEvent,
resultErrorEvents: signals.signals.signals2.errorEvents,
resultSuccessEvents: signals.signals.signals2.successEvents,
resultInvalidateEvent: signals.signals.signals2.invalidateEvent,
validationErrorEvents: signals.ids.ids1.errorEvents,
validationSuccessEvents: signals.ids.ids1.successEvents,
validationInvalidateEvent: signals.ids.ids1.invalidateEvent,
resultErrorEvents: signals.ids.ids2.errorEvents,
resultSuccessEvents: signals.ids.ids2.successEvents,
resultInvalidateEvent: signals.ids.ids2.invalidateEvent,
},

@@ -274,0 +274,0 @@ };

@@ -14,2 +14,3 @@ {

"strict": true,
"strictNullChecks": true,
"alwaysStrict": true,

@@ -16,0 +17,0 @@ "noImplicitAny": true,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc