Socket
Socket
Sign inDemoInstall

@agile-ts/core

Package Overview
Dependencies
Maintainers
1
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@agile-ts/core - npm Package Compare versions

Comparing version 0.0.5 to 0.0.6

dist/computed/computed.tracker.d.ts

10

CHANGELOG.md
# Change Log
## 0.0.6
### Patch Changes
- 86e6890: Updated Tests in Core | Fixed some Bugs
All notable changes to this project will be documented in this file.

@@ -10,8 +16,4 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## 0.0.4 (2020-11-03)
**Note:** Version bump only for package @agile-ts/core

53

dist/agile.d.ts

@@ -1,2 +0,2 @@

import { Runtime, Integration, State, Storage, StorageConfigInterface, Collection, DefaultItem, Computed, Event, EventConfig, DefaultEventPayload, Integrations, Observer, SubController } from "./internal";
import { Runtime, Integration, State, Storage, Collection, DefaultItem, Computed, Event, CreateEventConfigInterface, DefaultEventPayload, Integrations, Observer, SubController, Storages, CreateStorageConfigInterface, RegisterConfigInterface, Logger, CreateLoggerConfigInterface, StateConfigInterface } from "./internal";
export declare class Agile {

@@ -6,5 +6,6 @@ config: AgileConfigInterface;

subController: SubController;
storage: Storage;
storages: Storages;
integrations: Integrations;
static initialIntegrations: Integration[];
static logger: Logger;
/**

@@ -15,15 +16,9 @@ * @public

*/
constructor(config?: AgileConfigInterface);
constructor(config?: CreateAgileConfigInterface);
/**
* @public
* Integrates framework into Agile
* @param integration - Integration that gets registered/integrated
*/
use(integration: Integration): this;
/**
* @public
* Storage - Handy Interface for storing Items permanently
* @param config - Config
*/
Storage: (config: StorageConfigInterface) => Storage;
Storage: (config: CreateStorageConfigInterface) => Storage;
/**

@@ -33,5 +28,5 @@ * @public

* @param initialValue - Initial Value of the State
* @param key - Key/Name of the State
* @param config - Config
*/
State: <ValueType>(initialValue: ValueType, key?: string | undefined) => State<ValueType>;
State: <ValueType>(initialValue: ValueType, config?: StateConfigInterface) => State<ValueType>;
/**

@@ -42,3 +37,3 @@ * @public

*/
Collection: <DataType = DefaultItem>(config?: import("./collection").CollectionConfigInterface | ((collection: Collection<DataType>) => import("./collection").CollectionConfigInterface) | undefined) => Collection<DataType>;
Collection: <DataType = DefaultItem>(config?: import("./collection").CreateCollectionConfigInterface | ((collection: Collection<DataType>) => import("./collection").CreateCollectionConfigInterface) | undefined) => Collection<DataType>;
/**

@@ -56,14 +51,26 @@ * @public

*/
Event: <PayloadType = DefaultEventPayload>(config?: EventConfig | undefined) => Event<PayloadType>;
Event: <PayloadType = DefaultEventPayload>(config?: CreateEventConfigInterface | undefined) => Event<PayloadType>;
/**
* @public
* Configures Agile Storage
* @param storage - Storage that will get used as Agile Storage
* Integrates framework into Agile
* @param integration - Integration that gets registered/integrated
*/
configureStorage(storage: Storage): void;
integrate(integration: Integration): this;
/**
* @public
* Registers new Storage as Agile Storage
* @param storage - new Storage
* @param config - Config
*/
registerStorage(storage: Storage, config?: RegisterConfigInterface): this;
/**
* @public
* Checks if Agile has any registered Integration
*/
hasIntegration(): boolean;
/**
* @public
* Checks if Agile has any registered Storage
*/
hasStorage(): boolean;
}

@@ -75,6 +82,12 @@ /**

*/
export interface AgileConfigInterface {
logJobs?: boolean;
export interface CreateAgileConfigInterface {
logConfig?: CreateLoggerConfigInterface;
waitForMount?: boolean;
storageConfig?: StorageConfigInterface;
localStorage?: boolean;
}
/**
* @param waitForMount - If Agile should wait until the component mounts
*/
export interface AgileConfigInterface {
waitForMount: boolean;
}

@@ -12,3 +12,2 @@ "use strict";

constructor(config = {}) {
this.config = config;
//=========================================================================================================

@@ -30,5 +29,5 @@ // Storage

* @param initialValue - Initial Value of the State
* @param key - Key/Name of the State
* @param config - Config
*/
this.State = (initialValue, key) => new internal_1.State(this, initialValue, key);
this.State = (initialValue, config = {}) => new internal_1.State(this, initialValue, config);
//=========================================================================================================

@@ -52,5 +51,5 @@ // Collection

*/
this.Computed = (computeFunction, deps
// @ts-ignore
) => new internal_1.Computed(this, computeFunction, deps);
this.Computed = (computeFunction, deps) => new internal_1.Computed(this, computeFunction, {
computedDeps: deps,
});
//=========================================================================================================

@@ -65,11 +64,31 @@ // Event

this.Event = (config) => new internal_1.Event(this, config);
config = internal_1.defineConfig(config, {
localStorage: true,
waitForMount: false,
logConfig: {},
});
config.logConfig = internal_1.defineConfig(config.logConfig, {
prefix: "Agile",
active: true,
level: internal_1.Logger.level.WARN,
canUseCustomStyles: true,
allowedTags: ["runtime", "storage", "subscription", "multieditor"],
});
this.config = {
waitForMount: config.waitForMount,
};
this.integrations = new internal_1.Integrations(this);
this.runtime = new internal_1.Runtime(this);
this.subController = new internal_1.SubController(this);
this.storage = new internal_1.Storage(config.storageConfig || {});
this.storages = new internal_1.Storages(this, {
localStorage: config.localStorage,
});
// Assign customized config to Logger
Agile.logger = new internal_1.Logger(config.logConfig);
// Create global instance of Agile
internal_1.globalBind("__agile__", this);
if (!internal_1.globalBind("__agile__", this))
Agile.logger.warn("Be careful with multiple Agile Instances in one Application!");
}
//=========================================================================================================
// Use
// Integrate
//=========================================================================================================

@@ -81,3 +100,3 @@ /**

*/
use(integration) {
integrate(integration) {
this.integrations.integrate(integration);

@@ -87,16 +106,13 @@ return this;

//=========================================================================================================
// Set Storage
// Register Storage
//=========================================================================================================
/**
* @public
* Configures Agile Storage
* @param storage - Storage that will get used as Agile Storage
* Registers new Storage as Agile Storage
* @param storage - new Storage
* @param config - Config
*/
configureStorage(storage) {
// Get Observers that are already saved into a storage
const persistentInstances = this.storage.persistentInstances;
// Define new Storage
this.storage = storage;
// Transfer already saved items into new Storage
persistentInstances.forEach((persistent) => persistent.initialLoading(persistent.key));
registerStorage(storage, config = {}) {
this.storages.register(storage, config);
return this;
}

@@ -113,4 +129,20 @@ //=========================================================================================================

}
//=========================================================================================================
// Has Storage
//=========================================================================================================
/**
* @public
* Checks if Agile has any registered Storage
*/
hasStorage() {
return this.storages.hasStorage();
}
}
exports.Agile = Agile;
Agile.initialIntegrations = []; // External added Integrations
Agile.initialIntegrations = []; // External added initial Integrations
// Static Logger with default config -> will be overwritten by config of last created Agile Instance
Agile.logger = new internal_1.Logger({
prefix: "Agile",
active: true,
level: internal_1.Logger.level.WARN,
});

@@ -1,5 +0,5 @@

import { Agile, Collection, CollectionKey, GroupKey, ItemKey, Persistent, StorageKey } from "../internal";
import { Collection, CollectionKey, CreatePersistentConfigInterface, Group, GroupKey, ItemKey, Persistent, PersistentKey, StorageKey } from "../internal";
export declare class CollectionPersistent<DataType = any> extends Persistent {
collection: () => Collection;
private defaultGroupSideEffectKey;
collection: () => Collection<DataType>;
static defaultGroupSideEffectKey: string;
static storageItemKeyPattern: string;

@@ -10,39 +10,44 @@ static storageGroupKeyPattern: string;

* Collection Persist Manager - Handles permanent storing of Collection Value
* @param agileInstance - An instance of Agile
* @param collection - Collection that gets stored
* @param key - Key of Storage property
* @param config - Config
*/
constructor(agileInstance: Agile, collection: Collection<DataType>, key?: StorageKey);
set key(value: StorageKey);
get key(): StorageKey;
constructor(collection: Collection<DataType>, config?: CreatePersistentConfigInterface);
/**
* @public
* Sets Key/Name of Persistent
* @internal
* Updates Key/Name of Persistent
* @param value - New Key/Name of Persistent
*/
setKey(value: StorageKey): Promise<void>;
setKey(value?: StorageKey): Promise<void>;
/**
* @internal
* Loads Value from Storage
* Loads/Saves Storage Value for the first Time
*/
initialLoading(): Promise<void>;
/**
* @internal
* Loads Collection from Storage
* @param key - Prefix Key of Persisted Instances (default PersistentKey)
* @return Success?
*/
loadValue(): Promise<boolean>;
loadPersistedValue(key?: PersistentKey): Promise<boolean>;
/**
* @internal
* Saves/Updates Value in Storage
* Sets everything up so that the Collection gets saved in the Storage
* @param key - Prefix Key of Persisted Instances (default PersistentKey)
* @return Success?
*/
updateValue(): Promise<boolean>;
persistValue(key?: PersistentKey): Promise<boolean>;
/**
* @internal
* Removes Value form Storage
* Removes Collection from the Storage
* @param key - Prefix Key of Persisted Instances (default PersistentKey)
* @return Success?
*/
removeValue(): Promise<boolean>;
removePersistedValue(key?: PersistentKey): Promise<boolean>;
/**
* @internal
* Validates Storage Key
* @param key - Key that gets validated
* Formats Storage Key
* @param key - Key that gets formatted
*/
validateKey(key?: StorageKey): StorageKey | null;
formatKey(key?: StorageKey): StorageKey | undefined;
/**

@@ -52,4 +57,5 @@ * @internal

* @param group - Group
* @param key - Prefix Key of Persisted Instances (default PersistentKey)
*/
private rebuildStorageSideEffect;
rebuildStorageSideEffect(group: Group<DataType>, key?: PersistentKey): void;
/**

@@ -56,0 +62,0 @@ * @internal

@@ -18,20 +18,22 @@ "use strict";

* Collection Persist Manager - Handles permanent storing of Collection Value
* @param agileInstance - An instance of Agile
* @param collection - Collection that gets stored
* @param key - Key of Storage property
* @param config - Config
*/
constructor(agileInstance, collection, key) {
super(agileInstance);
this.defaultGroupSideEffectKey = "rebuildStorage";
constructor(collection, config = {}) {
super(collection.agileInstance(), {
instantiate: false,
});
config = internal_1.defineConfig(config, {
instantiate: true,
storageKeys: [],
});
this.collection = () => collection;
this.instantiatePersistent(key).then((success) => {
collection.isPersisted = success;
this.instantiatePersistent({
key: config.key,
storageKeys: config.storageKeys,
});
// Load/Store persisted Value/s for the first Time
if (this.ready && config.instantiate)
this.initialLoading();
}
set key(value) {
this.setKey(value);
}
get key() {
return this._key;
}
//=========================================================================================================

@@ -41,4 +43,4 @@ // Set Key

/**
* @public
* Sets Key/Name of Persistent
* @internal
* Updates Key/Name of Persistent
* @param value - New Key/Name of Persistent

@@ -48,54 +50,77 @@ */

return __awaiter(this, void 0, void 0, function* () {
// If persistent isn't ready try to init it with the new Key
if (!this.ready) {
this.instantiatePersistent(value).then((success) => {
this.collection().isPersisted = success;
});
const oldKey = this._key;
const wasReady = this.ready;
// Assign Key
if (value === this._key)
return;
this._key = value || internal_1.Persistent.placeHolderKey;
const isValid = this.validatePersistent();
// Try to Initial Load Value if persistent wasn't ready
if (!wasReady) {
if (isValid)
yield this.initialLoading();
return;
}
// Check if key has changed
if (value === this._key)
return;
// Remove value with old Key
yield this.removeValue();
// Update Key
this._key = value;
// Set value with new Key
yield this.updateValue();
// Remove value at old Key
yield this.removePersistedValue(oldKey);
// Assign Value to new Key
if (isValid)
yield this.persistValue(value);
});
}
//=========================================================================================================
// Load Value
// Initial Loading
//=========================================================================================================
/**
* @internal
* Loads Value from Storage
* Loads/Saves Storage Value for the first Time
*/
initialLoading() {
const _super = Object.create(null, {
initialLoading: { get: () => super.initialLoading }
});
return __awaiter(this, void 0, void 0, function* () {
_super.initialLoading.call(this).then(() => {
this.collection().isPersisted = true;
});
});
}
//=========================================================================================================
// Load Persisted Value
//=========================================================================================================
/**
* @internal
* Loads Collection from Storage
* @param key - Prefix Key of Persisted Instances (default PersistentKey)
* @return Success?
*/
loadValue() {
loadPersistedValue(key) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.ready)
return false;
const _key = key || this._key;
// Check if Collection is Persisted
const isPersisted = yield this.agileInstance().storage.get(this.key);
const isPersisted = yield this.agileInstance().storages.get(_key, this.defaultStorageKey);
if (!isPersisted)
return false;
// Load Values into Collection
// Loads Values into Collection
const loadValuesIntoCollection = () => __awaiter(this, void 0, void 0, function* () {
var _a, _b;
const primaryKey = this.collection().config.primaryKey || "id";
// Get Default Group
const defaultGroup = this.collection().getGroup(this.collection().config.defaultGroupKey || "default");
// Persist Default Group and instantiate it manually to await its instantiation
const groupStorageKey = CollectionPersistent.getGroupStorageKey(defaultGroup.key, this.collection().key);
defaultGroup.persist(groupStorageKey, { instantiate: false });
defaultGroup.isPersisted =
(yield ((_a = defaultGroup.persistent) === null || _a === void 0 ? void 0 : _a.instantiatePersistent(groupStorageKey))) || false;
// Add sideEffect to default Group which adds and removes Items from the Storage depending on the Group Value
if (!defaultGroup.hasSideEffect(this.defaultGroupSideEffectKey))
defaultGroup.addSideEffect(this.defaultGroupSideEffectKey, () => this.rebuildStorageSideEffect(defaultGroup));
// Load Storage Value from Items
for (let itemKey of defaultGroup.value) {
const defaultGroup = this.collection().getGroup(this.collection().config.defaultGroupKey);
if (!defaultGroup)
return false;
// Persist Default Group and load its Value manually to be 100% sure it got loaded
defaultGroup.persist({
instantiate: false,
followCollectionPersistKeyPattern: true,
});
if ((_a = defaultGroup.persistent) === null || _a === void 0 ? void 0 : _a.ready) {
yield ((_b = defaultGroup.persistent) === null || _b === void 0 ? void 0 : _b.initialLoading());
defaultGroup.isPersisted = true;
}
// Load Items into Collection
for (let itemKey of defaultGroup._value) {
const itemStorageKey = CollectionPersistent.getItemStorageKey(itemKey, _key);
// Get Storage Value
const storageValue = yield this.agileInstance().storage.get(CollectionPersistent.getItemStorageKey(itemKey, this.collection().key));
const storageValue = yield this.agileInstance().storages.get(itemStorageKey, this.defaultStorageKey);
if (!storageValue)

@@ -105,39 +130,43 @@ continue;

this.collection().collect(storageValue);
// Persist found Item that got created out of the Storage Value
(_b = this.collection()
.getItemById(storageValue[primaryKey])) === null || _b === void 0 ? void 0 : _b.persist(CollectionPersistent.getItemStorageKey(itemKey, this.collection().key));
}
return true;
});
yield loadValuesIntoCollection();
return true;
const success = yield loadValuesIntoCollection();
// Persist Collection, so that the Storage Value updates dynamically if the Collection updates
if (success)
yield this.persistValue(_key);
return success;
});
}
//=========================================================================================================
// Set Value
// Persist Value
//=========================================================================================================
/**
* @internal
* Saves/Updates Value in Storage
* Sets everything up so that the Collection gets saved in the Storage
* @param key - Prefix Key of Persisted Instances (default PersistentKey)
* @return Success?
*/
updateValue() {
persistValue(key) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.ready)
return false;
const _key = key || this._key;
const defaultGroup = this.collection().getGroup(this.collection().config.defaultGroupKey);
if (!defaultGroup)
return false;
// Set Collection to Persisted (in Storage)
this.agileInstance().storage.set(this.key, true);
// Get default Group
const defaultGroup = this.collection().getGroup(this.collection().config.defaultGroupKey || "default");
this.agileInstance().storages.set(_key, true, this.storageKeys);
// Persist default Group
defaultGroup.persist({ followCollectionPattern: true });
if (!defaultGroup.isPersisted)
defaultGroup.persist({ followCollectionPersistKeyPattern: true });
// Add sideEffect to default Group which adds and removes Items from the Storage depending on the Group Value
if (!defaultGroup.hasSideEffect(this.defaultGroupSideEffectKey))
defaultGroup.addSideEffect(this.defaultGroupSideEffectKey, () => this.rebuildStorageSideEffect(defaultGroup));
defaultGroup.addSideEffect(CollectionPersistent.defaultGroupSideEffectKey, () => this.rebuildStorageSideEffect(defaultGroup, _key));
// Persist Collection Items
for (let itemKey of defaultGroup.value) {
const item = this.collection().getItemById(itemKey);
const itemStorageKey = CollectionPersistent.getItemStorageKey(itemKey, this.collection().key);
for (let itemKey of defaultGroup._value) {
const item = this.collection().getItem(itemKey);
const itemStorageKey = CollectionPersistent.getItemStorageKey(itemKey, _key);
item === null || item === void 0 ? void 0 : item.persist(itemStorageKey);
}
this.collection().isPersisted = true;
this.isPersisted = true;
return true;

@@ -147,10 +176,11 @@ });

//=========================================================================================================
// Remove Value
// Remove Persisted Value
//=========================================================================================================
/**
* @internal
* Removes Value form Storage
* Removes Collection from the Storage
* @param key - Prefix Key of Persisted Instances (default PersistentKey)
* @return Success?
*/
removeValue() {
removePersistedValue(key) {
var _a, _b;

@@ -160,38 +190,39 @@ return __awaiter(this, void 0, void 0, function* () {

return false;
const _key = key || this._key;
const defaultGroup = this.collection().getGroup(this.collection().config.defaultGroupKey);
if (!defaultGroup)
return false;
// Set Collection to not Persisted
this.agileInstance().storage.remove(this.key);
// Get default Group
const defaultGroup = this.collection().getGroup(this.collection().config.defaultGroupKey || "default");
this.agileInstance().storages.remove(_key, this.storageKeys);
// Remove default Group from Storage
(_a = defaultGroup.persistent) === null || _a === void 0 ? void 0 : _a.removeValue();
// Remove sideEffect from default Group
defaultGroup.removeSideEffect(this.defaultGroupSideEffectKey);
(_a = defaultGroup.persistent) === null || _a === void 0 ? void 0 : _a.removePersistedValue();
// Remove Rebuild Storage sideEffect from default Group
defaultGroup.removeSideEffect(CollectionPersistent.defaultGroupSideEffectKey);
// Remove Collection Items from Storage
for (let itemKey of defaultGroup.value) {
const item = this.collection().getItemById(itemKey);
(_b = item === null || item === void 0 ? void 0 : item.persistent) === null || _b === void 0 ? void 0 : _b.removeValue();
for (let itemKey of defaultGroup._value) {
const item = this.collection().getItem(itemKey);
(_b = item === null || item === void 0 ? void 0 : item.persistent) === null || _b === void 0 ? void 0 : _b.removePersistedValue();
}
this.collection().isPersisted = false;
return false;
this.isPersisted = false;
return true;
});
}
//=========================================================================================================
// Validate Key
// Format Key
//=========================================================================================================
/**
* @internal
* Validates Storage Key
* @param key - Key that gets validated
* Formats Storage Key
* @param key - Key that gets formatted
*/
validateKey(key) {
formatKey(key) {
const collection = this.collection();
// Get key from Collection
if (!key && collection.key)
return collection.key;
// Return null if no key found
if (!key && collection._key)
return collection._key;
if (!key)
return null;
return;
// Set Storage Key to Collection Key if Collection has no key
if (!collection.key)
collection.key = key;
if (!collection._key)
collection._key = key;
return key;

@@ -206,15 +237,24 @@ }

* @param group - Group
* @param key - Prefix Key of Persisted Instances (default PersistentKey)
*/
rebuildStorageSideEffect(group) {
rebuildStorageSideEffect(group, key) {
var _a;
const collection = group.collection();
// Return if only an ItemKey got updated -> length stayed the same
if (group.previousStateValue.length === group.value.length)
const _key = key || ((_a = collection.persistent) === null || _a === void 0 ? void 0 : _a._key);
// Return if only a ItemKey got updated
if (group.previousStateValue.length === group._value.length)
return;
const addedKeys = group.value.filter((key) => !group.previousStateValue.includes(key));
const removedKeys = group.previousStateValue.filter((key) => !group.value.includes(key));
const addedKeys = group._value.filter((key) => !group.previousStateValue.includes(key));
const removedKeys = group.previousStateValue.filter((key) => !group._value.includes(key));
// Persist Added Keys
addedKeys.forEach((itemKey) => {
const item = collection.getItemById(itemKey);
if (!(item === null || item === void 0 ? void 0 : item.isPersisted))
item === null || item === void 0 ? void 0 : item.persist(CollectionPersistent.getItemStorageKey(itemKey, collection.key));
var _a;
const item = collection.getItem(itemKey);
const _itemKey = CollectionPersistent.getItemStorageKey(itemKey, _key);
if (!item)
return;
if (!item.isPersisted)
item.persist(_itemKey);
else
(_a = item.persistent) === null || _a === void 0 ? void 0 : _a.persistValue(_itemKey);
});

@@ -224,5 +264,8 @@ // Unpersist removed Keys

var _a;
const item = collection.getItemById(itemKey);
if (item === null || item === void 0 ? void 0 : item.isPersisted)
(_a = item === null || item === void 0 ? void 0 : item.persistent) === null || _a === void 0 ? void 0 : _a.removeValue();
const item = collection.getItem(itemKey);
const _itemKey = CollectionPersistent.getItemStorageKey(itemKey, _key);
if (!item)
return;
if (item.isPersisted)
(_a = item.persistent) === null || _a === void 0 ? void 0 : _a.removePersistedValue(_itemKey);
});

@@ -240,10 +283,8 @@ }

static getItemStorageKey(itemKey, collectionKey) {
if (!itemKey) {
console.error("Agile: Failed to build Item StorageKey");
if (!itemKey || !collectionKey)
internal_1.Agile.logger.warn("Failed to build unique Item StorageKey!");
if (!itemKey)
itemKey = "unknown";
}
if (!collectionKey) {
console.error("Agile: Failed to build Item StorageKey");
if (!collectionKey)
collectionKey = "unknown";
}
return this.storageItemKeyPattern

@@ -263,10 +304,8 @@ .replace("${collectionKey}", collectionKey.toString())

static getGroupStorageKey(groupKey, collectionKey) {
if (!groupKey) {
console.error("Agile: Failed to build Group StorageKey");
if (!groupKey || !collectionKey)
internal_1.Agile.logger.warn("Failed to build unique Group StorageKey!");
if (!groupKey)
groupKey = "unknown";
}
if (!collectionKey) {
console.error("Agile: Failed to build Group StorageKey");
if (!collectionKey)
collectionKey = "unknown";
}
return this.storageGroupKeyPattern

@@ -278,3 +317,4 @@ .replace("${collectionKey}", collectionKey.toString())

exports.CollectionPersistent = CollectionPersistent;
CollectionPersistent.defaultGroupSideEffectKey = "rebuildGroupStorageValue";
CollectionPersistent.storageItemKeyPattern = "_${collectionKey}_item_${itemKey}";
CollectionPersistent.storageGroupKeyPattern = "_${collectionKey}_group_${groupKey}";

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

import { Agile, State, Collection, DefaultItem, ItemKey, Item, StorageKey, StatePersistentConfigInterface } from "../internal";
import { State, Collection, DefaultItem, ItemKey, Item, StatePersistentConfigInterface, PersistentKey, StateRuntimeJobConfigInterface } from "../internal";
export declare class Group<DataType = DefaultItem> extends State<Array<ItemKey>> {
static rebuildGroupSideEffectKey: string;
collection: () => Collection<DataType>;

@@ -10,3 +11,2 @@ _output: Array<DataType>;

* Group - Holds Items of Collection
* @param agileInstance - An instance of Agile
* @param collection - Collection to that the Group belongs

@@ -16,3 +16,3 @@ * @param initialItems - Initial Key of Items in this Group

*/
constructor(agileInstance: Agile, collection: Collection<DataType>, initialItems?: Array<ItemKey>, config?: GroupConfigInterface);
constructor(collection: Collection<DataType>, initialItems?: Array<ItemKey>, config?: GroupConfigInterface);
/**

@@ -25,2 +25,7 @@ * @public

* @public
* Set Item Values of Group
*/
set output(value: DataType[]);
/**
* @public
* Get Items of Group

@@ -31,2 +36,7 @@ */

* @public
* Set Items of Group
*/
set items(value: Array<Item<DataType>>);
/**
* @public
* Checks if Group contains ItemKey

@@ -57,2 +67,10 @@ * @param itemKey - ItemKey that gets checked

* @public
* Replaces oldItemKey with newItemKey
* @param oldItemKey - Old ItemKey
* @param newItemKey - New ItemKey
* @param config - Config
*/
replace(oldItemKey: ItemKey, newItemKey: ItemKey, config?: StateRuntimeJobConfigInterface): this;
/**
* @public
* Stores Group Value into Agile Storage permanently

@@ -65,6 +83,6 @@ * @param config - Config

* Stores Group Value into Agile Storage permanently
* @param key - Storage Key (Note: not needed if Group has key/name)
* @param key - Key/Name of created Persistent (Note: Key required if Group has no set Key!)
* @param config - Config
*/
persist(key?: StorageKey, config?: GroupPersistConfigInterface): this;
persist(key?: PersistentKey, config?: GroupPersistConfigInterface): this;
/**

@@ -95,5 +113,7 @@ * @internal

* @param key - Key/Name of Group
* @param isPlaceholder - If Group is initially a Placeholder
*/
export interface GroupConfigInterface {
key?: GroupKey;
isPlaceholder?: boolean;
}

@@ -104,3 +124,3 @@ /**

export interface GroupPersistConfigInterface extends StatePersistentConfigInterface {
followCollectionPattern?: boolean;
followCollectionPersistKeyPattern?: boolean;
}

@@ -9,3 +9,2 @@ "use strict";

* Group - Holds Items of Collection
* @param agileInstance - An instance of Agile
* @param collection - Collection to that the Group belongs

@@ -15,4 +14,4 @@ * @param initialItems - Initial Key of Items in this Group

*/
constructor(agileInstance, collection, initialItems, config) {
super(agileInstance, initialItems || [], config === null || config === void 0 ? void 0 : config.key);
constructor(collection, initialItems, config = {}) {
super(collection.agileInstance(), initialItems || [], config);
this._output = []; // Output of Group

@@ -22,5 +21,5 @@ this._items = []; // Items of Group

this.collection = () => collection;
// Add rebuild to sideEffects so that it rebuilds the Group Output if the value changes
this.addSideEffect("buildGroup", () => this.rebuild());
// Initial Build
// Add rebuild to sideEffects to rebuild Group on Value Change
this.addSideEffect(Group.rebuildGroupSideEffectKey, () => this.rebuild());
// Initial Rebuild
this.rebuild();

@@ -33,5 +32,3 @@ }

get output() {
// Add Group to tracked Observers (for auto tracking used observers in computed function)
if (this.agileInstance().runtime.trackObservers)
this.agileInstance().runtime.foundObservers.add(this.observer);
internal_1.ComputedTracker.tracked(this.observer);
return this._output;

@@ -41,10 +38,22 @@ }

* @public
* Set Item Values of Group
*/
set output(value) {
this._output = value;
}
/**
* @public
* Get Items of Group
*/
get items() {
// Add Group to tracked Observers (for auto tracking used observers in computed function)
if (this.agileInstance().runtime.trackObservers)
this.agileInstance().runtime.foundObservers.add(this.observer);
internal_1.ComputedTracker.tracked(this.observer);
return this._items.map((item) => item());
}
/**
* @public
* Set Items of Group
*/
set items(value) {
this._items = value.map((item) => () => item);
}
//=========================================================================================================

@@ -82,4 +91,5 @@ // Has

const _itemKeys = internal_1.normalizeArray(itemKeys);
const notExistingItemKeysInCollection = [];
const notExistingItemKeys = [];
let newGroupValue = internal_1.copy(this.nextStateValue); // Copying nextStateValue because somehow a reference exists between nextStateValue and value
let newGroupValue = internal_1.copy(this.nextStateValue);
config = internal_1.defineConfig(config, {

@@ -92,17 +102,20 @@ background: false,

if (!newGroupValue.includes(itemKey)) {
console.error(`Agile: Couldn't find itemKey '${itemKey}' in Group!`, this);
internal_1.Agile.logger.error(`Couldn't find ItemKey '${itemKey}' in Group '${this._key}'!`);
notExistingItemKeys.push(itemKey);
notExistingItemKeysInCollection.push(itemKey);
return;
}
// Check if ItemKey exists in Collection
if (!this.collection().getItemById(itemKey))
notExistingItemKeys.push(itemKey);
if (!this.collection().getItem(itemKey))
notExistingItemKeysInCollection.push(itemKey);
// Remove ItemKey from Group
newGroupValue = newGroupValue.filter((key) => key !== itemKey);
});
this.nextStateValue = newGroupValue;
// Return if passed ItemKeys doesn't exist
if (notExistingItemKeys.length >= _itemKeys.length)
return this;
// If all removed ItemKeys doesn't exist in Collection -> no rerender necessary since output doesn't change
if (notExistingItemKeys.length >= _itemKeys.length)
if (notExistingItemKeysInCollection.length >= _itemKeys.length)
config.background = true;
// Ingest nextStateValue into Runtime
this.ingest({ background: config.background });
this.set(newGroupValue, { background: config.background });
return this;

@@ -121,4 +134,5 @@ }

const _itemKeys = internal_1.normalizeArray(itemKeys);
const notExistingItemKeys = []; // ItemKeys that don't exist in Collection
let newGroupValue = internal_1.copy(this.nextStateValue); // Copying nextStateValue because somehow a reference exists between nextStateValue and value
const notExistingItemKeysInCollection = [];
const existingItemKeys = [];
let newGroupValue = internal_1.copy(this.nextStateValue);
config = internal_1.defineConfig(config, {

@@ -133,10 +147,13 @@ method: "push",

// Check if ItemKey exists in Collection
if (!this.collection().getItemById(itemKey))
notExistingItemKeys.push(itemKey);
// Remove ItemKey from Group if it should get overwritten and exists
if (!this.collection().getItem(itemKey))
notExistingItemKeysInCollection.push(itemKey);
// Remove ItemKey from Group if it should get overwritten and already exists
if (existsInGroup) {
if (config.overwrite)
if (config.overwrite) {
newGroupValue = newGroupValue.filter((key) => key !== itemKey);
else
}
else {
existingItemKeys.push(itemKey);
return;
}
}

@@ -146,10 +163,28 @@ // Add new ItemKey to Group

});
this.nextStateValue = newGroupValue;
// If all added ItemKeys doesn't exist in Collection -> no rerender necessary since output doesn't change
if (notExistingItemKeys.length >= _itemKeys.length)
// Return if passed ItemKeys already exist
if (existingItemKeys.length >= _itemKeys.length)
return this;
// If all added ItemKeys doesn't exist in Collection or already exist -> no rerender necessary since output doesn't change
if (notExistingItemKeysInCollection.concat(existingItemKeys).length >=
_itemKeys.length)
config.background = true;
// Ingest nextStateValue into Runtime
this.ingest({ background: config.background });
this.set(newGroupValue, { background: config.background });
return this;
}
//=========================================================================================================
// Replace
//=========================================================================================================
/**
* @public
* Replaces oldItemKey with newItemKey
* @param oldItemKey - Old ItemKey
* @param newItemKey - New ItemKey
* @param config - Config
*/
replace(oldItemKey, newItemKey, config = {}) {
let newGroupValue = internal_1.copy(this._value);
newGroupValue.splice(newGroupValue.indexOf(oldItemKey), 1, newItemKey);
this.set(newGroupValue, config);
return this;
}
persist(keyOrConfig = {}, config = {}) {

@@ -160,3 +195,3 @@ let _config;

_config = keyOrConfig;
key = undefined;
key = this._key;
}

@@ -170,7 +205,11 @@ else {

followCollectionPattern: false,
storageKeys: [],
});
if (_config.followCollectionPattern) {
key = internal_1.CollectionPersistent.getGroupStorageKey(key || this.key, this.collection().key);
if (_config.followCollectionPersistKeyPattern) {
key = internal_1.CollectionPersistent.getGroupStorageKey(key || this._key, this.collection()._key);
}
super.persist(key, { instantiate: _config.instantiate });
super.persist(key, {
instantiate: _config.instantiate,
storageKeys: _config.storageKeys,
});
return this;

@@ -191,5 +230,5 @@ }

this._value.forEach((itemKey) => {
let data = this.collection().data[itemKey];
if (data)
groupItems.push(data);
const item = this.collection().getItem(itemKey);
if (item)
groupItems.push(item);
else

@@ -203,5 +242,6 @@ notFoundItemKeys.push(itemKey);

// Logging
if (this.agileInstance().config.logJobs && notFoundItemKeys.length > 0)
console.warn(`Agile: Couldn't find some Items in Collection '${this.key}'`, notFoundItemKeys);
this._items = groupItems.map((item) => () => item);
if (notFoundItemKeys.length > 0) {
internal_1.Agile.logger.warn(`Couldn't find some Items in Collection '${this.collection()._key}' (${this._key})`, notFoundItemKeys);
}
this.items = groupItems;
this._output = groupOutput;

@@ -212,1 +252,2 @@ this.notFoundItemKeys = notFoundItemKeys;

exports.Group = Group;
Group.rebuildGroupSideEffectKey = "rebuildGroup";

@@ -1,5 +0,6 @@

import { Agile, Item, Group, GroupKey, Selector, SelectorKey, StateKey, StorageKey, GroupConfigInterface, CollectionPersistent, GroupAddConfig } from "../internal";
import { Agile, Item, Group, GroupKey, Selector, SelectorKey, StorageKey, GroupConfigInterface, CollectionPersistent, GroupAddConfig } from "../internal";
export declare class Collection<DataType = DefaultItem> {
agileInstance: () => Agile;
config: CollectionConfigInterface;
private initialConfig;
size: number;

@@ -20,3 +21,3 @@ data: {

* @public
* Class that holds a List of Objects with key and causes rerender on subscribed Components
* Collection - Class that holds a List of Objects with key and causes rerender on subscribed Components
* @param agileInstance - An instance of Agile

@@ -30,3 +31,3 @@ * @param config - Config

*/
set key(value: StateKey | undefined);
set key(value: CollectionKey | undefined);
/**

@@ -36,3 +37,3 @@ * @public

*/
get key(): StateKey | undefined;
get key(): CollectionKey | undefined;
/**

@@ -43,3 +44,3 @@ * @public

*/
setKey(value: StateKey | undefined): void;
setKey(value: CollectionKey | undefined): this;
/**

@@ -65,3 +66,5 @@ * @public

*/
private initGroups;
initGroups(groups: {
[key: string]: Group<any>;
} | string[]): void;
/**

@@ -71,11 +74,13 @@ * @internal

*/
private initSelectors;
initSelectors(selectors: {
[key: string]: Selector<any>;
} | string[]): void;
/**
* @public
* Collect Item/s
* @param items - Item/s that get collected and added to this Collection
* @param groups - Add collected Item/s to certain Groups
* @param data - Data that gets added to Collection
* @param groupKeys - Add collected Item/s to certain Groups
* @param config - Config
*/
collect(items: DataType | Array<DataType>, groups?: GroupKey | Array<GroupKey>, config?: CollectConfigInterface<DataType>): this;
collect(data: DataType | Array<DataType>, groupKeys?: GroupKey | Array<GroupKey>, config?: CollectConfigInterface<DataType>): this;
/**

@@ -88,3 +93,3 @@ * @public

*/
update(itemKey: ItemKey, changes: DefaultItem | DataType, config?: UpdateConfigInterface): Item | undefined;
update(itemKey: ItemKey, changes: DefaultItem | DataType, config?: UpdateConfigInterface): Item<DataType> | undefined;
/**

@@ -99,17 +104,17 @@ * @public

* @public
* Creates new Selector that represents an Item of the Collection
* @param selectorKey - Name/Key of Selector
* @param itemKey - Key of Item which the Selector represents
* Get Group by Key/Name
* @param groupKey - Key/Name of Group
* @param config - Config
*/
createSelector(selectorKey: SelectorKey, itemKey: ItemKey): Selector<DataType>;
getGroup(groupKey: GroupKey | undefined, config?: GetGroupConfigInterface): Group<DataType> | undefined;
/**
* @public
* Get Group by Key/Name
* Get Group by Key/Name or a Reference to it if it doesn't exist yet
* @param groupKey - Name/Key of Group
*/
getGroup(groupKey: GroupKey): Group<DataType>;
getGroupWithReference(groupKey: GroupKey): Group<DataType>;
/**
* @public
* Removes Group by Key/Name
* @param groupKey - Name/Key of Selector
* @param groupKey - Name/Key of Group
*/

@@ -119,6 +124,20 @@ removeGroup(groupKey: GroupKey): this;

* @public
* Creates new Selector that represents an Item of the Collection
* @param selectorKey - Name/Key of Selector
* @param itemKey - Key of Item which the Selector represents
*/
createSelector(selectorKey: SelectorKey, itemKey: ItemKey): Selector<DataType>;
/**
* @public
* Get Selector by Key/Name
* @param selectorKey - Key/Name of Selector
* @param config - Config
*/
getSelector(selectorKey: SelectorKey | undefined, config?: GetSelectorConfigInterface): Selector<DataType> | undefined;
/**
* @public
* Get Selector by Key/Name or a Reference to it if it doesn't exist yet
* @param selectorKey - Name/Key of Selector
*/
getSelector(selectorKey: SelectorKey): Selector<DataType> | undefined;
getSelectorWithReference(selectorKey: SelectorKey): Selector<DataType>;
/**

@@ -132,29 +151,42 @@ * @public

* @public
* Remove Items from Group or from everywhere
* @param itemKeys - ItemKey/s that get removed
* Get Item by Key/Name
* @param itemKey - ItemKey of Item
* @param config - Config
*/
remove(itemKeys: ItemKey | Array<ItemKey>): {
fromGroups: (groups: Array<ItemKey> | ItemKey) => void;
everywhere: () => void;
};
getItem(itemKey: ItemKey | undefined, config?: GetItemConfigInterface): Item<DataType> | undefined;
/**
* @public
* Get Item by Id
* @param itemKey - ItemKey of Item that might get found
* Get Item by Key/Name or a Reference to it if it doesn't exist yet
* @param itemKey - Key/Name of Item
*/
getItemById(itemKey: ItemKey): Item<DataType> | undefined;
getItemWithReference(itemKey: ItemKey): Item<DataType>;
/**
* @public
* Get Value of Item by Id
* @param itemKey - ItemKey of ItemValue that might get found
* Get Value of Item by Key/Name
* @param itemKey - ItemKey of Item that holds the Value
* @param config - Config
*/
getValueById(itemKey: ItemKey): DataType | undefined;
getItemValue(itemKey: ItemKey | undefined, config?: GetItemConfigInterface): DataType | undefined;
/**
* @public
* Stores Collection Value in Agile Storage
* @param key - Storage Key (Note: not needed if Collection has key/name)
* Stores Collection Value into Agile Storage permanently
* @param config - Config
*/
persist(key?: StorageKey): this;
persist(config?: CollectionPersistentConfigInterface): this;
/**
* @public
* Stores Collection Value into Agile Storage permanently
* @param key - Key/Name of created Persistent (Note: Key required if Collection has no set Key!)
* @param config - Config
*/
persist(key?: StorageKey, config?: CollectionPersistentConfigInterface): this;
/**
* @public
* Callback Function that gets called if the persisted Value gets loaded into the Collection for the first Time
* Note: Only useful for persisted Collections!
* @param callback - Callback Function
*/
onLoad(callback: (success: boolean) => void): this;
/**
* @public
* Get count of registered Groups in Collection

@@ -183,3 +215,3 @@ */

* @internal
* Updates ItemKey of Item
* Updates Key/Name of Item in all Instances (Group, Selector, ..)
* @param oldItemKey - Old ItemKey

@@ -189,5 +221,20 @@ * @param newItemKey - New ItemKey

*/
private updateItemKey;
updateItemKey(oldItemKey: ItemKey, newItemKey: ItemKey, config?: UpdateItemKeyConfigInterface): boolean;
/**
* @public
* Gets GroupKeys that contain the passed ItemKey
* @param itemKey - ItemKey
*/
getGroupKeysThatHaveItemKey(itemKey: ItemKey): Array<GroupKey>;
/**
* @public
* Remove Items from Collection
* @param itemKeys - ItemKey/s that get removed
*/
remove(itemKeys: ItemKey | Array<ItemKey>): {
fromGroups: (groups: Array<ItemKey> | ItemKey) => void;
everywhere: () => void;
};
/**
* @public
* Removes Item/s from Group/s

@@ -200,4 +247,4 @@ * @param itemKeys - ItemKey/s that get removed from Group/s

* @public
* Removes Item/s from Group/s
* @param itemKeys - ItemKey/s of Item/s that get removed from Collection
* Removes Item completely from Collection
* @param itemKeys - ItemKey/s of Item/s
*/

@@ -207,10 +254,7 @@ removeItems(itemKeys: ItemKey | Array<ItemKey>): void;

* @internal
* Creates/Updates Item from provided Data and adds it to the Collection
* @param data - Data from which the Item gets created/updated
* Updates existing or creates Item from provided Data
* @param data - Data
* @param config - Config
*/
setData(data: DataType, config?: {
patch?: boolean;
background?: boolean;
}): boolean;
setData(data: DataType, config?: SetDataConfigInterface): boolean;
/**

@@ -236,3 +280,3 @@ * @internal

*/
export interface CollectionConfigInterface {
export interface CreateCollectionConfigInterface {
groups?: {

@@ -249,2 +293,10 @@ [key: string]: Group<any>;

/**
* @param primaryKey - Name of Property that holds the PrimaryKey (default = id)
* @param defaultGroupKey - Key/Name of Default Group that holds all collected Items
*/
export interface CollectionConfigInterface {
primaryKey: string;
defaultGroupKey: ItemKey;
}
/**
* @param patch - If Item gets patched into existing Item with the same Id

@@ -254,2 +306,3 @@ * @param method - Way of adding Item to Collection (push, unshift)

* @param background - If collecting an Item happens in the background (-> not causing any rerender)
* @param select - If collected Items get selected with a Selector
*/

@@ -261,2 +314,3 @@ export interface CollectConfigInterface<DataType = any> {

background?: boolean;
select?: boolean;
}

@@ -279,10 +333,44 @@ /**

* @param background - If assigning a new value happens in the background (-> not causing any rerender)
* @param forceRerender - Force rerender no matter what happens
* @param sideEffects - If Side Effects of State get executed
* @param force - Force creating and performing Job
* @param sideEffects - If Side Effects of Group gets executed
*/
export interface RebuildGroupsThatIncludeItemKeyConfigInterface {
background?: boolean;
forceRerender?: boolean;
force?: boolean;
sideEffects?: boolean;
}
export declare type CollectionConfig<DataType = DefaultItem> = CollectionConfigInterface | ((collection: Collection<DataType>) => CollectionConfigInterface);
/**
* @param notExisting - If also official not existing Items like Placeholder get found
*/
export interface GetItemConfigInterface {
notExisting?: boolean;
}
/**
* @param notExisting - If also official not existing Groups like Placeholder get found
*/
export interface GetGroupConfigInterface {
notExisting?: boolean;
}
/**
* @param notExisting - If also official not existing Selectors like Placeholder get found
*/
export interface GetSelectorConfigInterface {
notExisting?: boolean;
}
/**
* @param instantiate - If Persistent gets instantiated
* @param storageKeys - Key/Name of Storages which gets used to persist the Collection Value (NOTE: If not passed the default Storage will be used)
*/
export interface CollectionPersistentConfigInterface {
instantiate?: boolean;
storageKeys?: StorageKey[];
}
/**
* @param patch - If Data gets patched into existing Item
* @param background - If assigning Data happens in background
*/
export interface SetDataConfigInterface {
patch?: boolean;
background?: boolean;
}
export declare type CollectionConfig<DataType = DefaultItem> = CreateCollectionConfigInterface | ((collection: Collection<DataType>) => CreateCollectionConfigInterface);

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

* @public
* Class that holds a List of Objects with key and causes rerender on subscribed Components
* Collection - Class that holds a List of Objects with key and causes rerender on subscribed Components
* @param agileInstance - An instance of Agile

@@ -16,10 +16,15 @@ * @param config - Config

this.data = {}; // Collection Data
this.isPersisted = false; // If Collection is stored in Storage
this.isPersisted = false; // If Collection can be stored in Agile Storage (-> successfully integrated persistent)
this.groups = {};
this.selectors = {};
this.agileInstance = () => agileInstance;
if (typeof config === "function")
config = config(this);
this.config = internal_1.defineConfig(config, {
// Set temp Config for creating proper Placeholder Items (of Selector)
this.config = {
defaultGroupKey: "default",
primaryKey: "id",
};
// Assign Properties
let _config = typeof config === "function" ? config(this) : config;
_config = internal_1.defineConfig(_config, {
primaryKey: "id",
groups: {},

@@ -29,5 +34,10 @@ selectors: {},

});
this._key = this.config.key;
this.initGroups();
this.initSelectors();
this._key = _config.key;
this.config = {
defaultGroupKey: _config.defaultGroupKey,
primaryKey: _config.primaryKey,
};
this.initialConfig = _config;
this.initGroups(_config.groups);
this.initSelectors(_config.selectors);
}

@@ -57,10 +67,10 @@ /**

setKey(value) {
var _a, _b;
const oldKey = this._key;
// Update State Key
this._key = value;
// Update Key in PersistManager
if (value !== undefined &&
this.persistent &&
this.persistent.key === oldKey)
this.persistent.key = value;
// Update Key in Persistent (only if oldKey equal to persistentKey -> otherwise the PersistentKey got formatted and will be set where other)
if (value && ((_a = this.persistent) === null || _a === void 0 ? void 0 : _a._key) === oldKey)
(_b = this.persistent) === null || _b === void 0 ? void 0 : _b.setKey(value);
return this;
}

@@ -77,3 +87,3 @@ //=========================================================================================================

Group(initialItems, config) {
return new internal_1.Group(this.agileInstance(), this, initialItems, config);
return new internal_1.Group(this, initialItems, config);
}

@@ -99,11 +109,10 @@ //=========================================================================================================

*/
initGroups() {
const groups = internal_1.copy(this.config.groups);
initGroups(groups) {
if (!groups)
return;
let groupsObject = {};
// If groups is Array of SelectorNames transform it to Selector Object
// If groups is Array of GroupNames transform it to Group Object
if (Array.isArray(groups)) {
groups.forEach((groupKey) => {
groupsObject[groupKey] = new internal_1.Group(this.agileInstance(), this, [], {
groupsObject[groupKey] = new internal_1.Group(this, [], {
key: groupKey,

@@ -116,9 +125,9 @@ });

// Add default Group
groupsObject[this.config.defaultGroupKey || "default"] = new internal_1.Group(this.agileInstance(), this, [], {
key: this.config.defaultGroupKey || "default",
groupsObject[this.config.defaultGroupKey] = new internal_1.Group(this, [], {
key: this.config.defaultGroupKey,
});
// Set Key/Name of Group to property Name
for (let key in groupsObject)
if (!groupsObject[key].key)
groupsObject[key].key = key;
if (!groupsObject[key]._key)
groupsObject[key].setKey(key);
this.groups = groupsObject;

@@ -133,4 +142,3 @@ }

*/
initSelectors() {
const selectors = internal_1.copy(this.config.selectors);
initSelectors(selectors) {
if (!selectors)

@@ -151,4 +159,4 @@ return;

for (let key in selectorsObject)
if (!selectorsObject[key].key)
selectorsObject[key].key = key;
if (!selectorsObject[key]._key)
selectorsObject[key].setKey(key);
this.selectors = selectorsObject;

@@ -162,11 +170,11 @@ }

* Collect Item/s
* @param items - Item/s that get collected and added to this Collection
* @param groups - Add collected Item/s to certain Groups
* @param data - Data that gets added to Collection
* @param groupKeys - Add collected Item/s to certain Groups
* @param config - Config
*/
collect(items, groups, config = {}) {
const _items = internal_1.normalizeArray(items);
const groupKeys = internal_1.normalizeArray(groups);
const defaultGroupKey = this.config.defaultGroupKey || "default";
const primaryKey = this.config.primaryKey || "id";
collect(data, groupKeys, config = {}) {
const _data = internal_1.normalizeArray(data);
const _groupKeys = internal_1.normalizeArray(groupKeys);
const defaultGroupKey = this.config.defaultGroupKey;
const primaryKey = this.config.primaryKey;
config = internal_1.defineConfig(config, {

@@ -176,12 +184,11 @@ method: "push",

patch: false,
select: false,
});
// Add default GroupKey, because Items get always added to default Group
if (!groupKeys.includes(defaultGroupKey))
groupKeys.push(defaultGroupKey);
if (!_groupKeys.includes(defaultGroupKey))
_groupKeys.push(defaultGroupKey);
// Create not existing Groups
groupKeys.forEach((groupName) => !this.groups[groupName] && this.createGroup(groupName));
// Instantiate Items
_items.forEach((data, index) => {
_groupKeys.forEach((key) => !this.groups[key] && this.createGroup(key));
_data.forEach((data, index) => {
const itemKey = data[primaryKey];
const itemExistsInCollection = !!this.data[itemKey];
// Add Item to Collection

@@ -194,15 +201,6 @@ const success = this.setData(data, {

return this;
// Ingest Groups that include the ItemKey into Runtime, which than rebuilds the Group (because output of group changed)
if (!itemExistsInCollection) {
for (let groupKey in this.groups) {
const group = this.getGroup(groupKey);
if (group.value.includes(itemKey)) {
if (!config.background)
group.ingest({ forceRerender: true, storage: false });
}
}
}
// Add ItemKey to provided Groups
groupKeys.forEach((groupKey) => {
this.groups[groupKey].add(itemKey, {
_groupKeys.forEach((groupKey) => {
var _a;
(_a = this.getGroup(groupKey)) === null || _a === void 0 ? void 0 : _a.add(itemKey, {
method: config.method,

@@ -212,2 +210,4 @@ background: config.background,

});
if (config.select)
this.createSelector(itemKey, itemKey);
if (config.forEachItem)

@@ -229,34 +229,34 @@ config.forEachItem(data, itemKey, index);

update(itemKey, changes, config = {}) {
if (!this.data.hasOwnProperty(itemKey)) {
console.error(`Agile: ItemKey '${itemKey} doesn't exist in Collection!`, this);
const item = this.getItem(itemKey, { notExisting: true });
const primaryKey = this.config.primaryKey;
config = internal_1.defineConfig(config, {
addNewProperties: false,
background: false,
});
if (!item) {
internal_1.Agile.logger.error(`ItemKey '${itemKey}' doesn't exist in Collection '${this._key}'!`);
return undefined;
}
if (!internal_1.isValidObject(changes)) {
console.error(`Agile: Changes have to be an Object!`, this);
internal_1.Agile.logger.error(`You have to pass an valid Changes Object to update '${itemKey}' in '${this._key}'!`);
return undefined;
}
const item = this.data[itemKey];
const primaryKey = this.config.primaryKey || "";
config = internal_1.defineConfig(config, {
addNewProperties: true,
background: false,
});
// Merge changes into ItemValue
// Merge changes into current ItemValue
const newItemValue = internal_1.flatMerge(internal_1.copy(item.nextStateValue), changes, {
addNewProperties: config.addNewProperties,
});
const oldItemKey = item.value[primaryKey];
const oldItemKey = item._value[primaryKey];
const newItemKey = newItemValue[primaryKey];
const updateItemKey = oldItemKey !== newItemKey;
const updatedItemKey = oldItemKey !== newItemKey;
// Apply changes to Item
item.set(newItemValue, {
background: config.background,
storage: !updateItemKey,
storage: !updatedItemKey,
});
// Update ItemKey of Item
if (updateItemKey)
if (updatedItemKey)
this.updateItemKey(oldItemKey, newItemKey, {
background: config.background,
});
return this.data[newItemValue[primaryKey]];
return item;
}

@@ -272,61 +272,62 @@ //=========================================================================================================

*/
createGroup(groupKey, initialItems) {
if (this.groups.hasOwnProperty(groupKey)) {
console.warn(`Agile: Group with the name '${groupKey}' already exists!`);
return this.groups[groupKey];
createGroup(groupKey, initialItems = []) {
let group = this.getGroup(groupKey, { notExisting: true });
// Check if Group already exists
if (group) {
if (!group.isPlaceholder) {
internal_1.Agile.logger.warn(`Group with the name '${groupKey}' already exists!`);
return group;
}
group.set(initialItems, { overwrite: true });
return group;
}
// Create new Group
const group = new internal_1.Group(this.agileInstance(), this, initialItems, { key: groupKey });
// Create Group
group = new internal_1.Group(this, initialItems, { key: groupKey });
this.groups[groupKey] = group;
// Logging
if (this.agileInstance().config.logJobs)
console.log(`Agile: Created new Group called '${groupKey}'`, group);
return group;
}
//=========================================================================================================
// Create Selector
// Get Group
//=========================================================================================================
/**
* @public
* Creates new Selector that represents an Item of the Collection
* @param selectorKey - Name/Key of Selector
* @param itemKey - Key of Item which the Selector represents
* Get Group by Key/Name
* @param groupKey - Key/Name of Group
* @param config - Config
*/
createSelector(selectorKey, itemKey) {
if (this.selectors.hasOwnProperty(selectorKey)) {
console.warn(`Agile: The Selector with the name '${selectorKey}' already exists!`);
return this.selectors[selectorKey];
}
// Create new Selector
const selector = new internal_1.Selector(this, itemKey, {
key: selectorKey,
getGroup(groupKey, config = {}) {
config = internal_1.defineConfig(config, {
notExisting: false,
});
this.selectors[selectorKey] = selector;
// Logging
if (this.agileInstance().config.logJobs)
console.log(`Agile: Created Selector called '${selectorKey}'`, selector);
return selector;
// Get Group
const group = groupKey ? this.groups[groupKey] : undefined;
// Check if Group exists
if (!group || (!config.notExisting && group.isPlaceholder))
return undefined;
internal_1.ComputedTracker.tracked(group.observer);
return group;
}
//=========================================================================================================
// Get Group
// Get Group With Reference
//=========================================================================================================
/**
* @public
* Get Group by Key/Name
* Get Group by Key/Name or a Reference to it if it doesn't exist yet
* @param groupKey - Name/Key of Group
*/
getGroup(groupKey) {
if (!this.groups[groupKey]) {
console.warn(`Agile: Group with the key/name '${groupKey}' doesn't exist!`);
// Return empty group because it might get annoying to handle with undefined (can check if it exists with group.exists)
const group = new internal_1.Group(this.agileInstance(), this, [], {
key: "dummy",
getGroupWithReference(groupKey) {
let group = this.getGroup(groupKey, { notExisting: true });
// Create dummy Group to hold reference
if (!group) {
group = new internal_1.Group(this, [], {
key: groupKey,
isPlaceholder: true,
});
group.isPlaceholder = true;
return group;
this.groups[groupKey] = group;
}
return this.groups[groupKey];
internal_1.ComputedTracker.tracked(group.observer);
return group;
}
//=========================================================================================================
// Remove Selector
// Remove Group
//=========================================================================================================

@@ -336,7 +337,7 @@ /**

* Removes Group by Key/Name
* @param groupKey - Name/Key of Selector
* @param groupKey - Name/Key of Group
*/
removeGroup(groupKey) {
if (!this.groups[groupKey]) {
console.warn(`Agile: Group with the key/name '${groupKey}' doesn't exist!`);
internal_1.Agile.logger.warn(`Group with the key/name '${groupKey}' doesn't exist!`);
return this;

@@ -348,2 +349,29 @@ }

//=========================================================================================================
// Create Selector
//=========================================================================================================
/**
* @public
* Creates new Selector that represents an Item of the Collection
* @param selectorKey - Name/Key of Selector
* @param itemKey - Key of Item which the Selector represents
*/
createSelector(selectorKey, itemKey) {
let selector = this.getSelector(selectorKey, { notExisting: true });
// Check if Selector already exists
if (selector) {
if (!selector.isPlaceholder) {
internal_1.Agile.logger.warn(`Selector with the name '${selectorKey}' already exists!`);
return selector;
}
selector.select(itemKey, { overwrite: true });
return selector;
}
// Create Selector
selector = new internal_1.Selector(this, itemKey, {
key: selectorKey,
});
this.selectors[selectorKey] = selector;
return selector;
}
//=========================================================================================================
// Get Selector

@@ -354,10 +382,37 @@ //=========================================================================================================

* Get Selector by Key/Name
* @param selectorKey - Key/Name of Selector
* @param config - Config
*/
getSelector(selectorKey, config = {}) {
config = internal_1.defineConfig(config, {
notExisting: false,
});
// Get Selector
const selector = selectorKey ? this.selectors[selectorKey] : undefined;
// Check if Selector exists
if (!selector || (!config.notExisting && selector.isPlaceholder))
return undefined;
internal_1.ComputedTracker.tracked(selector.observer);
return selector;
}
//=========================================================================================================
// Get Selector With Reference
//=========================================================================================================
/**
* @public
* Get Selector by Key/Name or a Reference to it if it doesn't exist yet
* @param selectorKey - Name/Key of Selector
*/
getSelector(selectorKey) {
if (!this.selectors[selectorKey]) {
console.warn(`Agile: Selector with the key/name '${selectorKey}' doesn't exist!`);
return undefined;
getSelectorWithReference(selectorKey) {
let selector = this.getSelector(selectorKey, { notExisting: true });
// Create dummy Selector to hold reference
if (!selector) {
selector = new internal_1.Selector(this, "unknown", {
key: selectorKey,
isPlaceholder: true,
});
this.selectors[selectorKey] = selector;
}
return this.selectors[selectorKey];
internal_1.ComputedTracker.tracked(selector.observer);
return selector;
}

@@ -373,6 +428,8 @@ //=========================================================================================================

removeSelector(selectorKey) {
var _a;
if (!this.selectors[selectorKey]) {
console.warn(`Agile: Selector with the key/name '${selectorKey}' doesn't exist!`);
internal_1.Agile.logger.warn(`Selector with the key/name '${selectorKey}' doesn't exist!`);
return this;
}
(_a = this.selectors[selectorKey]) === null || _a === void 0 ? void 0 : _a.unselect(); // Unselects current selected Item
delete this.selectors[selectorKey];

@@ -382,30 +439,40 @@ return this;

//=========================================================================================================
// Remove
// Get Item by Id
//=========================================================================================================
/**
* @public
* Remove Items from Group or from everywhere
* @param itemKeys - ItemKey/s that get removed
* Get Item by Key/Name
* @param itemKey - ItemKey of Item
* @param config - Config
*/
remove(itemKeys) {
return {
fromGroups: (groups) => this.removeFromGroups(itemKeys, groups),
everywhere: () => this.removeItems(itemKeys),
};
getItem(itemKey, config = {}) {
config = internal_1.defineConfig(config, {
notExisting: false,
});
// Get Item
const item = itemKey ? this.data[itemKey] : undefined;
// Check if Item exists
if (!item || (!config.notExisting && !item.exists))
return undefined;
internal_1.ComputedTracker.tracked(item.observer);
return item;
}
//=========================================================================================================
// Get Item by Id
//=========================================================================================================
/**
* @public
* Get Item by Id
* @param itemKey - ItemKey of Item that might get found
* Get Item by Key/Name or a Reference to it if it doesn't exist yet
* @param itemKey - Key/Name of Item
*/
getItemById(itemKey) {
if (!this.data.hasOwnProperty(itemKey) || !this.data[itemKey].exists)
return undefined;
const item = this.data[itemKey];
// Add State to tracked Observers (for auto tracking used observers in computed function)
if (this.agileInstance().runtime.trackObservers)
this.agileInstance().runtime.foundObservers.add(item.observer);
getItemWithReference(itemKey) {
let item = this.getItem(itemKey, { notExisting: true });
// Create dummy Item to hold reference
if (!item) {
item = new internal_1.Item(this, {
[this.config.primaryKey]: itemKey,
dummy: "item",
}, {
isPlaceholder: true,
});
this.data[itemKey] = item;
}
internal_1.ComputedTracker.tracked(item.observer);
return item;

@@ -418,7 +485,8 @@ }

* @public
* Get Value of Item by Id
* @param itemKey - ItemKey of ItemValue that might get found
* Get Value of Item by Key/Name
* @param itemKey - ItemKey of Item that holds the Value
* @param config - Config
*/
getValueById(itemKey) {
let item = this.getItemById(itemKey);
getItemValue(itemKey, config = {}) {
let item = this.getItem(itemKey, config);
if (!item)

@@ -428,23 +496,50 @@ return undefined;

}
persist(keyOrConfig = {}, config = {}) {
let _config;
let key;
if (internal_1.isValidObject(keyOrConfig)) {
_config = keyOrConfig;
key = this._key;
}
else {
_config = config || {};
key = keyOrConfig;
}
_config = internal_1.defineConfig(_config, {
instantiate: true,
storageKeys: [],
});
if (this.persistent)
internal_1.Agile.logger.warn(`By persisting the Collection '${this._key}' twice you overwrite the old Persistent Instance!`);
// Create persistent -> Persist Value
this.persistent = new internal_1.CollectionPersistent(this, {
instantiate: _config.instantiate,
storageKeys: _config.storageKeys,
key: key,
});
return this;
}
//=========================================================================================================
// Persist
// On Load
//=========================================================================================================
/**
* @public
* Stores Collection Value in Agile Storage
* @param key - Storage Key (Note: not needed if Collection has key/name)
* Callback Function that gets called if the persisted Value gets loaded into the Collection for the first Time
* Note: Only useful for persisted Collections!
* @param callback - Callback Function
*/
persist(key) {
// Update Persistent Key
onLoad(callback) {
if (this.persistent) {
if (key)
this.persistent.key = key;
return this;
this.persistent.onLoad = callback;
// If Collection is already 'isPersisted' the loading was successful -> callback can be called
if (this.isPersisted)
callback(true);
}
// Create persistent -> Persist Value
this.persistent = new internal_1.CollectionPersistent(this.agileInstance(), this, key);
else {
internal_1.Agile.logger.error(`Please make sure you persist the Collection '${this._key}' before using the 'onLoad' function!`);
}
return this;
}
//=========================================================================================================
// Group Size
// Get Group Count
//=========================================================================================================

@@ -462,3 +557,3 @@ /**

//=========================================================================================================
// Selector Size
// Get Selector Count
//=========================================================================================================

@@ -484,18 +579,11 @@ /**

var _a, _b;
// Remove Items from Storage
for (let key in this.data) {
const item = this.getItemById(key);
(_a = item === null || item === void 0 ? void 0 : item.persistent) === null || _a === void 0 ? void 0 : _a.removeValue();
}
// Reset Groups
for (let key in this.groups)
(_b = this.getGroup(key)) === null || _b === void 0 ? void 0 : _b.reset();
// Reset Data
this.data = {};
this.size = 0;
// Reselect Items
for (let key in this.selectors) {
const selector = this.getSelector(key);
selector === null || selector === void 0 ? void 0 : selector.select(selector === null || selector === void 0 ? void 0 : selector.itemKey, { force: true });
}
// Reset Groups
for (let key in this.groups)
(_a = this.getGroup(key)) === null || _a === void 0 ? void 0 : _a.reset();
// Reset Selectors
for (let key in this.selectors)
(_b = this.getSelector(key)) === null || _b === void 0 ? void 0 : _b.reset();
}

@@ -517,6 +605,4 @@ //=========================================================================================================

_groupKeys.forEach((groupKey) => {
const group = this.getGroup(groupKey);
_itemKeys.forEach((itemKey) => {
group === null || group === void 0 ? void 0 : group.add(itemKey, config);
});
var _a;
(_a = this.getGroup(groupKey)) === null || _a === void 0 ? void 0 : _a.add(_itemKeys, config);
});

@@ -529,3 +615,3 @@ }

* @internal
* Updates ItemKey of Item
* Updates Key/Name of Item in all Instances (Group, Selector, ..)
* @param oldItemKey - Old ItemKey

@@ -535,4 +621,5 @@ * @param newItemKey - New ItemKey

*/
updateItemKey(oldItemKey, newItemKey, config) {
const item = this.getItemById(oldItemKey);
updateItemKey(oldItemKey, newItemKey, config = {}) {
var _a;
const item = this.getItem(oldItemKey, { notExisting: true });
config = internal_1.defineConfig(config, {

@@ -542,3 +629,3 @@ background: false,

if (!item || oldItemKey === newItemKey)
return;
return false;
// Remove Item from old ItemKey and add Item to new ItemKey

@@ -548,25 +635,64 @@ delete this.data[oldItemKey];

// Update Key/Name of Item
item.key = newItemKey;
// Update persist Key of Item (Doesn't get changed by setting new item key because PersistKey is not ItemKey)
item.persist(internal_1.CollectionPersistent.getItemStorageKey(newItemKey, this.key));
// Update Groups
for (let groupName in this.groups) {
const group = this.getGroup(groupName);
if (group.isPlaceholder || !group.has(oldItemKey))
item.setKey(newItemKey);
// Update persist Key of Item (Doesn't get updated by updating key of Item because PersistKey is special formatted)
(_a = item.persistent) === null || _a === void 0 ? void 0 : _a.setKey(internal_1.CollectionPersistent.getItemStorageKey(newItemKey, this._key));
// Update ItemKey in Groups
for (let groupKey in this.groups) {
const group = this.getGroup(groupKey, { notExisting: true });
if (!group || !group.has(oldItemKey))
continue;
// Replace old ItemKey with new ItemKey
const newGroupValue = internal_1.copy(group.value);
newGroupValue.splice(newGroupValue.indexOf(oldItemKey), 1, newItemKey);
group.set(newGroupValue, { background: config === null || config === void 0 ? void 0 : config.background });
group.replace(oldItemKey, newItemKey, { background: config === null || config === void 0 ? void 0 : config.background });
}
// Update Selectors
for (let selectorName in this.selectors) {
const selector = this.getSelector(selectorName);
if (!selector || selector.itemKey !== oldItemKey)
// Update ItemKey in Selectors
for (let selectorKey in this.selectors) {
const selector = this.getSelector(selectorKey, { notExisting: true });
if (!selector)
continue;
// Replace old selected ItemKey with new ItemKey
selector.select(newItemKey, { background: config === null || config === void 0 ? void 0 : config.background });
// Reselect Item in existing Selector which has selected the newItemKey
if (selector.hasSelected(newItemKey)) {
selector.select(newItemKey, {
force: true,
background: config === null || config === void 0 ? void 0 : config.background,
});
}
// Select newItemKey in existing Selector which has selected the oldItemKey
if (selector.hasSelected(oldItemKey))
selector.select(newItemKey, {
background: config === null || config === void 0 ? void 0 : config.background,
});
}
return true;
}
//=========================================================================================================
// Get GroupKeys That Have ItemKey
//=========================================================================================================
/**
* @public
* Gets GroupKeys that contain the passed ItemKey
* @param itemKey - ItemKey
*/
getGroupKeysThatHaveItemKey(itemKey) {
const groupKeys = [];
for (let groupKey in this.groups) {
const group = this.getGroup(groupKey, { notExisting: true });
if (group === null || group === void 0 ? void 0 : group.has(itemKey))
groupKeys.push(groupKey);
}
return groupKeys;
}
//=========================================================================================================
// Remove
//=========================================================================================================
/**
* @public
* Remove Items from Collection
* @param itemKeys - ItemKey/s that get removed
*/
remove(itemKeys) {
return {
fromGroups: (groups) => this.removeFromGroups(itemKeys, groups),
everywhere: () => this.removeItems(itemKeys),
};
}
//=========================================================================================================
// Remove From Groups

@@ -587,4 +713,4 @@ //=========================================================================================================

_groupKeys.forEach((groupKey) => {
const group = this.getGroup(groupKey);
if (!group)
const group = this.getGroup(groupKey, { notExisting: true });
if (!group || !group.has(itemKey))
return;

@@ -594,4 +720,5 @@ group.remove(itemKey);

});
// If Item got removed from every Groups in Collection, remove it completely
if (removedFromGroupsCount >= this.getGroupCount())
// If Item got removed from every Groups the Item was in, remove it completely
if (removedFromGroupsCount >=
this.getGroupKeysThatHaveItemKey(itemKey).length)
this.removeItems(itemKey);

@@ -605,4 +732,4 @@ });

* @public
* Removes Item/s from Group/s
* @param itemKeys - ItemKey/s of Item/s that get removed from Collection
* Removes Item completely from Collection
* @param itemKeys - ItemKey/s of Item/s
*/

@@ -613,3 +740,3 @@ removeItems(itemKeys) {

var _a;
const item = this.getItemById(itemKey);
const item = this.getItem(itemKey, { notExisting: true });
if (!item)

@@ -619,16 +746,16 @@ return;

for (let groupKey in this.groups) {
const group = this.getGroup(groupKey);
if (group.has(itemKey))
group.remove(itemKey);
const group = this.getGroup(groupKey, { notExisting: true });
if (group === null || group === void 0 ? void 0 : group.has(itemKey))
group === null || group === void 0 ? void 0 : group.remove(itemKey);
}
// Remove Selectors that represents this Item
for (let selectorKey in this.selectors) {
const selector = this.getSelector(selectorKey);
if ((selector === null || selector === void 0 ? void 0 : selector.itemKey) === itemKey)
this.removeSelector(selectorKey);
}
// Remove Item from Storage
(_a = item.persistent) === null || _a === void 0 ? void 0 : _a.removeValue();
(_a = item.persistent) === null || _a === void 0 ? void 0 : _a.removePersistedValue();
// Remove Item from Collection
delete this.data[itemKey];
// Reselect Item in Selectors (to create new dummyItem that holds reference)
for (let selectorKey in this.selectors) {
const selector = this.getSelector(selectorKey, { notExisting: true });
if (selector === null || selector === void 0 ? void 0 : selector.hasSelected(itemKey))
selector === null || selector === void 0 ? void 0 : selector.select(itemKey, { force: true });
}
this.size--;

@@ -642,9 +769,9 @@ });

* @internal
* Creates/Updates Item from provided Data and adds it to the Collection
* @param data - Data from which the Item gets created/updated
* Updates existing or creates Item from provided Data
* @param data - Data
* @param config - Config
*/
setData(data, config = {}) {
const _data = data; // Transformed Data to any because of unknown Object (DataType)
const primaryKey = this.config.primaryKey || "id";
const _data = internal_1.copy(data); // Transformed Data to any because of unknown Object (DataType)
const primaryKey = this.config.primaryKey;
config = internal_1.defineConfig(config, {

@@ -655,25 +782,25 @@ patch: false,

if (!internal_1.isValidObject(_data)) {
console.error("Agile: Collections items has to be an object!");
internal_1.Agile.logger.error(`Item Data of Collection '${this._key}' has to be an valid Object!`);
return false;
}
if (!_data.hasOwnProperty(primaryKey)) {
console.error(`Agile: Collection Item needs a primary Key property called '${this.config.primaryKey}'!`);
internal_1.Agile.logger.error(`Collection '${this._key}' Item Data has to contain a primaryKey property called '${this.config.primaryKey}'!`);
return false;
}
const itemKey = _data[primaryKey];
let item = this.data[itemKey];
let item = this.getItem(itemKey, { notExisting: true });
const wasPlaceholder = (item === null || item === void 0 ? void 0 : item.isPlaceholder) || false;
const createItem = !item;
// Create or update Item
if (item && config.patch)
item = item.patch(_data, { background: config.background });
if (item && !config.patch)
item = item.set(_data, { background: config.background });
if (!item) {
if (!createItem && config.patch)
item === null || item === void 0 ? void 0 : item.patch(_data, { background: config.background });
if (!createItem && !config.patch)
item === null || item === void 0 ? void 0 : item.set(_data, { background: config.background });
if (createItem) {
item = new internal_1.Item(this, _data);
this.data[itemKey] = item;
}
// Increase size of Collection
if (createItem || wasPlaceholder)
this.size++;
}
// Reset isPlaceholder of Item since it got an value
if (item.isPlaceholder)
item.isPlaceholder = false;
// Set new Item at itemKey
this.data[itemKey] = item;
return true;

@@ -693,3 +820,2 @@ }

background: false,
forceRerender: !(config === null || config === void 0 ? void 0 : config.background),
sideEffects: true,

@@ -700,7 +826,7 @@ });

const group = this.getGroup(groupKey);
if (group.has(itemKey)) {
if (group === null || group === void 0 ? void 0 : group.has(itemKey)) {
// group.rebuild(); Not necessary because a sideEffect of the Group is to rebuild it self
group.ingest({
group === null || group === void 0 ? void 0 : group.ingest({
background: config === null || config === void 0 ? void 0 : config.background,
forceRerender: config === null || config === void 0 ? void 0 : config.forceRerender,
force: true,
sideEffects: config === null || config === void 0 ? void 0 : config.sideEffects,

@@ -707,0 +833,0 @@ storage: false,

import { State, Collection, DefaultItem, StateKey } from "../internal";
export declare class Item<DataType = DefaultItem> extends State<DataType> {
private collection;
static updateGroupSideEffectKey: string;
isSelected: boolean;
collection: () => Collection<DataType>;
/**

@@ -9,14 +11,17 @@ * @public

* @param data - Data that the Item holds
* @param config - Config
*/
constructor(collection: Collection, data: DataType);
constructor(collection: Collection<DataType>, data: DataType, config?: ItemConfigInterface);
/**
* @public
* Set Key/Name of Item
* @internal
* Updates Key/Name of State
* @param value - New Key/Name of State
*/
set key(value: StateKey | undefined);
/**
* @public
* Get Key/Name of Item
*/
get key(): StateKey | undefined;
setKey(value: StateKey | undefined): this;
}
/**
* @param isPlaceholder - If Item is initially a Placeholder
*/
export interface ItemConfigInterface {
isPlaceholder?: boolean;
}

@@ -11,33 +11,36 @@ "use strict";

* @param data - Data that the Item holds
* @param config - Config
*/
constructor(collection, data) {
var _a;
super(collection.agileInstance(), data);
constructor(collection, data, config = {}) {
super(collection.agileInstance(), data, {
isPlaceholder: config.isPlaceholder,
key: data[collection.config.primaryKey],
});
this.isSelected = false; // If Item is selected by a Selector
this.collection = () => collection;
// Setting primaryKey of Data to Key/Name of Item
this.key = data[((_a = collection.config) === null || _a === void 0 ? void 0 : _a.primaryKey) || "id"];
// Reassign Key to assign sideEffects
this.setKey(data[collection.config.primaryKey]);
}
//=========================================================================================================
// Set Key
//=========================================================================================================
/**
* @public
* Set Key/Name of Item
* @internal
* Updates Key/Name of State
* @param value - New Key/Name of State
*/
set key(value) {
// Note can't use 'super.key' because of 'https://github.com/Microsoft/TypeScript/issues/338'
this.setKey(value);
setKey(value) {
super.setKey(value);
if (!value)
return;
// Update rebuildGroupThatIncludePrimaryKey SideEffect
this.removeSideEffect("rebuildGroup");
this.addSideEffect("rebuildGroup", (properties) => this.collection().rebuildGroupsThatIncludeItemKey(value, properties));
return this;
// Remove old rebuildGroupsThatIncludeItemKey sideEffect
this.removeSideEffect(Item.updateGroupSideEffectKey);
// Add rebuildGroupsThatIncludeItemKey to sideEffects to rebuild Groups that include this Item if it changes
this.addSideEffect(Item.updateGroupSideEffectKey, (config) => this.collection().rebuildGroupsThatIncludeItemKey(value, config));
// Initial Rebuild
this.collection().rebuildGroupsThatIncludeItemKey(value);
return this;
}
/**
* @public
* Get Key/Name of Item
*/
get key() {
// Note can't use 'super.key' because of 'https://github.com/Microsoft/TypeScript/issues/338'
// Can't remove this getter function.. because the setter function is set in this class -> Error if not setter and getter function set
return this._key;
}
}
exports.Item = Item;
Item.updateGroupSideEffectKey = "rebuildGroup";

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

import { Collection, DefaultItem, Item, ItemKey, State } from "../internal";
import { Collection, DefaultItem, Item, ItemKey, State, StateRuntimeJobConfigInterface } from "../internal";
export declare class Selector<DataType = DefaultItem> extends State<DataType | undefined> {
static dummyItemKey: string;
static rebuildSelectorSideEffectKey: string;
collection: () => Collection<DataType>;

@@ -26,13 +28,24 @@ item: Item<DataType> | undefined;

* @public
* Select new ItemKey that the Selector will represents
* Select new ItemKey
* @param itemKey - New ItemKey
* @param config - Config
*/
select(itemKey: ItemKey, config?: SelectConfigInterface): this;
select(itemKey: ItemKey, config?: StateRuntimeJobConfigInterface): this;
/**
* @public
* Unselects current selected Item
* @param config - Config
*/
unselect(config?: StateRuntimeJobConfigInterface): this;
/**
* Checks if Selector has selected passed ItemKey
* @param itemKey
*/
hasSelected(itemKey: ItemKey): boolean;
/**
* @public
* Rebuilds Selector
* @param config - Config
*/
rebuildSelector(config?: SelectConfigInterface): void;
rebuildSelector(config?: StateRuntimeJobConfigInterface): void;
}

@@ -42,15 +55,7 @@ export declare type SelectorKey = string | number;

* @param key - Key/Name of Selector
* @param isPlaceholder - If Selector is initially a Placeholder
*/
export interface SelectorConfigInterface {
key?: SelectorKey;
isPlaceholder?: boolean;
}
/**
* @param background - If selecting a new Item happens in the background (-> not causing any rerender)
* @param sideEffects - If Side Effects of Selector get executed
* @param force - Force to select ItemKey
*/
export interface SelectConfigInterface {
background?: boolean;
sideEffects?: boolean;
force?: boolean;
}

@@ -13,10 +13,15 @@ "use strict";

*/
constructor(collection, itemKey, config) {
super(collection.agileInstance(), collection.getValueById(itemKey));
constructor(collection, itemKey, config = {}) {
super(collection.agileInstance(), undefined, config);
config = internal_1.defineConfig(config, {
isPlaceholder: false,
});
this.collection = () => collection;
this.item = undefined;
this._itemKey = itemKey;
this.key = config === null || config === void 0 ? void 0 : config.key;
this._itemKey = Selector.dummyItemKey;
this._key = config === null || config === void 0 ? void 0 : config.key;
this.isPlaceholder = true;
// Initial Select
this.select(itemKey);
if (!config.isPlaceholder)
this.select(itemKey, { overwrite: true });
}

@@ -37,5 +42,8 @@ /**

}
//=========================================================================================================
// Select
//=========================================================================================================
/**
* @public
* Select new ItemKey that the Selector will represents
* Select new ItemKey
* @param itemKey - New ItemKey

@@ -45,4 +53,6 @@ * @param config - Config

select(itemKey, config = {}) {
const oldItem = this.item;
let newItem = this.collection().getItemById(itemKey);
const oldItem = this.collection().getItem(this._itemKey, {
notExisting: true,
}); // Because this.item might be outdated
let newItem = this.collection().getItemWithReference(itemKey);
config = internal_1.defineConfig(config, {

@@ -52,22 +62,16 @@ background: false,

force: false,
overwrite: (oldItem === null || oldItem === void 0 ? void 0 : oldItem.isPlaceholder) || false,
storage: true,
});
if ((oldItem === null || oldItem === void 0 ? void 0 : oldItem.key) === itemKey && !config.force) {
console.warn(`Agile: Selector has already selected key '${itemKey}'!`);
if (this.hasSelected(itemKey) && !config.force) {
internal_1.Agile.logger.warn(`Selector has already selected '${itemKey}'!`);
return this;
}
// Remove old Item from Collection if it is an Placeholder
if (oldItem === null || oldItem === void 0 ? void 0 : oldItem.isPlaceholder)
delete this.collection().data[this.itemKey];
// Create dummy Item to hold reference if Item with ItemKey doesn't exist
if (!newItem) {
newItem = new internal_1.Item(this.collection(), { id: itemKey });
newItem.isPlaceholder = true;
this.collection().data[itemKey] = newItem;
}
// Remove Selector sideEffect from old Item
oldItem === null || oldItem === void 0 ? void 0 : oldItem.removeSideEffect("rebuildSelector");
// Unselect old Item
this.unselect({ background: true });
this._itemKey = itemKey;
this.item = newItem;
// Add Selector sideEffect to Item
newItem.addSideEffect("rebuildSelector", () => this.rebuildSelector(config));
newItem.isSelected = true;
// Add SideEffect to newItem, that rebuild this Selector depending on the current Item Value
newItem.addSideEffect(Selector.rebuildSelectorSideEffectKey, (config) => this.rebuildSelector(config));
// Rebuild Selector for instantiating new 'selected' ItemKey properly

@@ -78,6 +82,46 @@ this.rebuildSelector(config);

//=========================================================================================================
// RebuildSelector
// Unselect
//=========================================================================================================
/**
* @public
* Unselects current selected Item
* @param config - Config
*/
unselect(config = {}) {
// Because this.item might be outdated
const item = this.collection().getItem(this._itemKey, {
notExisting: true,
});
// Unselect Item
if (item) {
item.isSelected = false;
item.removeSideEffect(Selector.rebuildSelectorSideEffectKey);
if (item.isPlaceholder)
delete this.collection().data[this._itemKey];
}
// Reset and rebuild Selector
this.item = undefined;
this._itemKey = Selector.dummyItemKey;
this.rebuildSelector(config);
this.isPlaceholder = true;
return this;
}
//=========================================================================================================
// Has Selected
//=========================================================================================================
/**
* Checks if Selector has selected passed ItemKey
* @param itemKey
*/
hasSelected(itemKey) {
const isSelected = this._itemKey === itemKey;
if (!this.item)
return isSelected;
return isSelected && this.item.isSelected;
}
//=========================================================================================================
// Rebuild Selector
//=========================================================================================================
/**
* @public
* Rebuilds Selector

@@ -87,23 +131,13 @@ * @param config - Config

rebuildSelector(config = {}) {
var _a, _b;
config = internal_1.defineConfig(config, {
background: false,
sideEffects: true,
});
// Set Selector Value to undefined if Item doesn't exist
if (!this.item || this.item.isPlaceholder) {
this._value = undefined;
this.set(undefined, config);
return;
}
// Assign ItemValue to Selector
this.nextStateValue = internal_1.copy((_a = this.item) === null || _a === void 0 ? void 0 : _a.value);
// Fix initialStateValue and previousStateValue if they are still set from the Placeholder
if (internal_1.equal(this.item.initialStateValue, { id: this.itemKey }))
this.item.initialStateValue = internal_1.copy((_b = this.item) === null || _b === void 0 ? void 0 : _b.nextStateValue);
if (internal_1.equal(this.item.previousStateValue, { id: this.itemKey }))
this.item.previousStateValue = internal_1.copy(this.nextStateValue);
// Ingest nextStateValue into Runtime
this.ingest(config);
// Set Selector Value to updated Item Value
this.set(this.item._value, config);
}
}
exports.Selector = Selector;
Selector.dummyItemKey = "unknown";
Selector.rebuildSelectorSideEffectKey = "rebuildSelector";

@@ -1,2 +0,2 @@

import { State, Agile, Observer, StorageKey, StatePersistentConfigInterface } from "../internal";
import { State, Agile, Observer, StorageKey, StatePersistentConfigInterface, Event, StateConfigInterface } from "../internal";
export declare class Computed<ComputedValueType = any> extends State<ComputedValueType> {

@@ -12,19 +12,8 @@ agileInstance: () => Agile;

* @param computeFunction - Function for computing value
* @param deps - Hard coded dependencies of Computed Function
* @param config - Config
*/
constructor(agileInstance: Agile, computeFunction: () => ComputedValueType, deps?: Array<Observer | State | Event>);
constructor(agileInstance: Agile, computeFunction: () => ComputedValueType, config?: ComputedConfigInterface);
/**
* @public
* Set Value of Computed
*/
set value(value: ComputedValueType);
/**
* @public
* Get Value of Computed
*/
get value(): ComputedValueType;
/**
* @public
* Recomputes Function Value
* -> Calls ComputeFunction and updates Dependencies of it
* Recomputes Value of Computed
* @param config - Config

@@ -40,3 +29,3 @@ */

*/
updateComputeFunction(computeFunction: () => ComputedValueType, deps?: Array<Observer | State | Event>, config?: RecomputeConfigInterface): void;
updateComputeFunction(computeFunction: () => ComputedValueType, deps?: Array<Observer | State | Event>, config?: UpdateComputeFunctionInterface): void;
/**

@@ -47,2 +36,8 @@ * @internal

computeValue(): ComputedValueType;
/**
* @internal
* Gets Observer out of passed Instances
* @param instances - Instances that hold an Observer
*/
formatDeps(instances: Array<any>): Array<Observer>;
patch(): this;

@@ -53,2 +48,8 @@ persist(keyOrConfig?: StorageKey | StatePersistentConfigInterface, config?: StatePersistentConfigInterface): this;

/**
* @param computedDeps - Hard coded dependencies of Computed Function
*/
export interface ComputedConfigInterface extends StateConfigInterface {
computedDeps?: Array<Observer | State | Event>;
}
/**
* @param background - If recomputing value happens in the background (-> not causing any rerender)

@@ -61,1 +62,7 @@ * @param sideEffects - If Side Effects of Computed get executed

}
/**
* @param overwriteDeps - If old hardCoded deps get overwritten
*/
export interface UpdateComputeFunctionInterface extends RecomputeConfigInterface {
overwriteDeps?: boolean;
}

@@ -11,35 +11,22 @@ "use strict";

* @param computeFunction - Function for computing value
* @param deps - Hard coded dependencies of Computed Function
* @param config - Config
*/
constructor(agileInstance, computeFunction, deps = []) {
super(agileInstance, computeFunction());
this.deps = []; // All Dependencies of Computed
this.hardCodedDeps = [];
constructor(agileInstance, computeFunction, config = {}) {
super(agileInstance, computeFunction(), {
key: config.key,
deps: config.deps,
});
this.deps = []; // All Dependencies of Computed (hardCoded and autoDetected)
this.hardCodedDeps = []; // HardCoded Dependencies of Computed
config = internal_1.defineConfig(config, {
computedDeps: [],
});
this.agileInstance = () => agileInstance;
this.computeFunction = computeFunction;
this.hardCodedDeps = deps
.map((dep) => dep["observer"] || undefined)
.filter((dep) => dep !== undefined);
// Format hardCodedDeps
this.hardCodedDeps = this.formatDeps(config.computedDeps);
this.deps = this.hardCodedDeps;
// Recompute for setting initial value and adding missing dependencies
this.recompute();
}
/**
* @public
* Set Value of Computed
*/
set value(value) {
console.error("Agile: You can't mutate Computed value!");
}
/**
* @public
* Get Value of Computed
*/
get value() {
// Note can't use 'super.value' because of 'https://github.com/Microsoft/TypeScript/issues/338'
// Can't remove this getter function.. since the setter function is set in this class -> Error if not setter and getter function set
// Add State to tracked Observers (for auto tracking used observers in computed function)
if (this.agileInstance().runtime.trackObservers)
this.agileInstance().runtime.foundObservers.add(this.observer);
return this._value;
}
//=========================================================================================================

@@ -50,7 +37,6 @@ // Recompute

* @public
* Recomputes Function Value
* -> Calls ComputeFunction and updates Dependencies of it
* Recomputes Value of Computed
* @param config - Config
*/
recompute(config) {
recompute(config = {}) {
config = internal_1.defineConfig(config, {

@@ -72,9 +58,22 @@ background: false,

*/
updateComputeFunction(computeFunction, deps = [], config) {
updateComputeFunction(computeFunction, deps = [], config = {}) {
config = internal_1.defineConfig(config, {
background: false,
sideEffects: true,
overwriteDeps: true,
});
// Update deps
const newDeps = this.formatDeps(deps);
if (config.overwriteDeps)
this.hardCodedDeps = newDeps;
else
this.hardCodedDeps = this.hardCodedDeps.concat(newDeps);
this.deps = this.hardCodedDeps;
// Update computeFunction
this.computeFunction = computeFunction;
this.hardCodedDeps = deps
.map((dep) => dep["observer"] || undefined)
.filter((dep) => dep !== undefined);
// Recompute for setting initial Computed Function Value and adding missing Dependencies
this.recompute(config);
this.recompute({
background: config.background,
sideEffects: config.sideEffects,
});
}

@@ -89,13 +88,11 @@ //=========================================================================================================

computeValue() {
this.agileInstance().runtime.trackObservers = true;
// Auto track Observers the computeFunction might depend on
internal_1.ComputedTracker.track();
const computedValue = this.computeFunction();
// Get tracked Observers and disable Tracking Observers
let foundDeps = Array.from(this.agileInstance().runtime.getTrackedObservers());
let foundDeps = internal_1.ComputedTracker.getTrackedObservers();
// Handle foundDeps and hardCodedDeps
const newDeps = [];
this.hardCodedDeps.concat(foundDeps).forEach((observer) => {
if (!observer)
return;
newDeps.push(observer);
// Make this Observer depending on Observer -> If value of Observer changes it will ingest this Observer into the Runtime
// Make this Observer depending on foundDep Observer
observer.depend(this.observer);

@@ -107,14 +104,36 @@ });

//=========================================================================================================
// Overwriting some functions which can't be used in Computed
// Format Deps
//=========================================================================================================
/**
* @internal
* Gets Observer out of passed Instances
* @param instances - Instances that hold an Observer
*/
formatDeps(instances) {
const finalInstances = [];
for (let instance of instances) {
if (instance instanceof internal_1.Observer) {
finalInstances.push(instance);
continue;
}
if (instance !== undefined &&
instance["observer"] !== undefined &&
instance["observer"] instanceof internal_1.Observer)
finalInstances.push(instance["observer"]);
}
return finalInstances;
}
//=========================================================================================================
// Overwriting some functions which aren't allowed to use in Computed
//=========================================================================================================
patch() {
console.error("Agile: You can't use patch method on Computed Function!");
internal_1.Agile.logger.error("You can't use patch method on ComputedState!");
return this;
}
persist(keyOrConfig = {}, config = {}) {
console.error("Agile: You can't use persist method on Computed Function!");
internal_1.Agile.logger.error("You can't use persist method on ComputedState!");
return this;
}
invert() {
console.error("Agile: You can't use invert method on Computed Function!");
internal_1.Agile.logger.error("You can't use invert method on ComputedState!");
return this;

@@ -121,0 +140,0 @@ }

@@ -1,2 +0,2 @@

import { Agile, Observer, Job, ObserverKey, Event } from "../internal";
import { Observer, RuntimeJob, ObserverKey, Event, SubscriptionContainer, IngestConfigInterface, RuntimeJobConfigInterface, RuntimeJobKey } from "../internal";
export declare class EventObserver<PayloadType = any> extends Observer {

@@ -7,13 +7,12 @@ event: () => Event<PayloadType>;

* Event Observer - Handles Event dependencies and ingests Event triggers into the Runtime
* @param {Agile} agileInstance - An instance of Agile
* @param {Event} event - Event
* @param {Array<Observer>} deps - Initial Dependencies of the Event
* @param {ObserverKey} key - Key/Name of Event Observer
* @param event - Event
* @param config - Config
*/
constructor(agileInstance: Agile, event: Event<PayloadType>, deps?: Array<Observer>, key?: ObserverKey);
constructor(event: Event<PayloadType>, config?: CreateEventObserverConfigInterface);
/**
* @internal
* Triggers a rerender on Components which got subscribed by this Event
* Ingests Event into Runtime and causes Rerender on Components that got subscribed by the Event (Observer)
* @param config - Config
*/
trigger(): void;
trigger(config?: EventIngestConfigInterface): void;
/**

@@ -24,3 +23,19 @@ * @internal

*/
perform(job: Job<this>): void;
perform(job: RuntimeJob<this>): void;
}
/**
* @param deps - Initial Dependencies of Event Observer
* @param subs - Initial Subscriptions of Event Observer
* @param key - Key/Name of Event Observer
*/
export interface CreateEventObserverConfigInterface {
deps?: Array<Observer>;
subs?: Array<SubscriptionContainer>;
key?: ObserverKey;
}
/**
* @param key - Key/Name of Job that gets created
*/
export interface EventIngestConfigInterface extends RuntimeJobConfigInterface, IngestConfigInterface {
key?: RuntimeJobKey;
}

@@ -9,9 +9,11 @@ "use strict";

* Event Observer - Handles Event dependencies and ingests Event triggers into the Runtime
* @param {Agile} agileInstance - An instance of Agile
* @param {Event} event - Event
* @param {Array<Observer>} deps - Initial Dependencies of the Event
* @param {ObserverKey} key - Key/Name of Event Observer
* @param event - Event
* @param config - Config
*/
constructor(agileInstance, event, deps, key) {
super(agileInstance, deps, key);
constructor(event, config = {}) {
super(event.agileInstance(), {
deps: config.deps,
key: config.key,
subs: config.subs,
});
this.event = () => event;

@@ -24,6 +26,22 @@ }

* @internal
* Triggers a rerender on Components which got subscribed by this Event
* Ingests Event into Runtime and causes Rerender on Components that got subscribed by the Event (Observer)
* @param config - Config
*/
trigger() {
this.agileInstance().runtime.ingest(this, {});
trigger(config = {}) {
config = internal_1.defineConfig(config, {
perform: true,
background: false,
sideEffects: true,
force: false,
});
// Create Job
const job = new internal_1.RuntimeJob(this, {
force: config.force,
sideEffects: config.sideEffects,
background: config.background,
key: config.key || this._key,
});
this.agileInstance().runtime.ingest(job, {
perform: config.perform,
});
}

@@ -30,0 +48,0 @@ //=========================================================================================================

@@ -1,6 +0,7 @@

import { Agile } from "../internal";
import { Agile, EventJob, Observer } from "../internal";
import { EventObserver } from "./event.observer";
export declare class Event<PayloadType = DefaultEventPayload> {
agileInstance: () => Agile;
config: EventConfig;
config: EventConfigInterface;
private initialConfig;
_key?: EventKey;

@@ -11,6 +12,6 @@ uses: number;

};
private currentTimeout;
private queue;
enabled: boolean;
observer: EventObserver;
currentTimeout: any;
queue: Array<EventJob>;
payload: PayloadType;

@@ -23,3 +24,3 @@ /**

*/
constructor(agileInstance: Agile, config?: EventConfig);
constructor(agileInstance: Agile, config?: CreateEventConfigInterface);
/**

@@ -36,2 +37,8 @@ * @public

/**
* @internal
* Set Key/Name of Event
* @param value - New Key/Name of Event
*/
setKey(value: EventKey | undefined): this;
/**
* @public

@@ -52,7 +59,7 @@ * Registers new Callback Function that will be called if this Event gets triggered

* @public
* Triggers Event
* -> Calls all registered Callback Functions
* Triggers Events
* @param payload - Payload that gets passed into the Callback Functions
* @param keys - Keys of Callback Functions that get triggered (Note: if not passed all registered Events will be triggered)
*/
trigger(payload?: PayloadType): this;
trigger(payload: PayloadType, keys?: string[]): this;
/**

@@ -81,10 +88,15 @@ * @public

* @internal
* Triggers Event
* Triggers normal Event
* @param payload - Payload that gets passed into the Callback Functions
* @param keys - Keys of Callback Functions that get triggered (Note: if not passed all registered Events will be triggered)
*/
private normalTrigger;
normalTrigger(payload: PayloadType, keys?: string[]): void;
/**
* @internal
* Triggers Event with some delay (config.delay)
* Triggers async Event (Events with a delay)
* @param payload - Payload that gets passed into the Callback Functions
* @param delay - Delay until Events get triggered
* @param keys - Keys of Callback Functions that get triggered (Note: if not passed all registered Events will be triggered)
*/
private delayedTrigger;
delayedTrigger(payload: PayloadType, delay: number, keys?: string[]): void;
}

@@ -95,3 +107,3 @@ export declare type EventKey = string | number;

};
export declare type EventCallbackFunction<PayloadType = DefaultEventPayload> = (payload?: PayloadType) => void;
export declare type EventCallbackFunction<PayloadType = DefaultEventPayload> = (payload: PayloadType) => void;
/**

@@ -101,6 +113,8 @@ * @param key - Key/Name of Event

* @param maxUses - How often the Event can be used/triggered
* @param delay - Delayed call of Event Callback Functions in seconds
* @param delay - Delayed call of Event Callback Functions in milliseconds
* @param overlap - If Events can overlap
* @param rerender - If triggering an Event should cause a rerender
* @param deps - Initial deps of State
*/
export interface EventConfig {
export interface CreateEventConfigInterface {
key?: EventKey;

@@ -110,3 +124,17 @@ enabled?: boolean;

delay?: number;
overlap?: boolean;
rerender?: boolean;
deps?: Array<Observer>;
}
/**
* @param maxUses - How often the Event can be used/triggered
* @param delay - Delayed call of Event Callback Functions in seconds
* @param overlap - If Events can overlap
* @param rerender - If triggering an Event should cause a rerender
*/
export interface EventConfigInterface {
maxUses?: number;
delay?: number;
overlap?: boolean;
rerender: boolean;
}

@@ -16,13 +16,26 @@ "use strict";

this.callbacks = {}; // All 'subscribed' callback function
this.queue = []; // Queue of delayed triggers
this.enabled = true;
this.queue = []; // Queue of delayed Events
this.agileInstance = () => agileInstance;
this.config = internal_1.defineConfig(config, {
config = internal_1.defineConfig(config, {
enabled: true,
rerender: false,
maxUses: undefined,
delay: undefined,
overlap: false,
deps: [],
});
this.observer = new event_observer_1.EventObserver(agileInstance, this, [], this.config.key);
this._key = this.config.key;
this.enabled =
this.config.enabled !== undefined ? this.config.enabled : true;
this._key = config.key;
this.observer = new event_observer_1.EventObserver(this, {
key: config.key,
deps: config.deps,
});
this.enabled = config.enabled;
this.config = {
rerender: config.rerender,
delay: config.delay,
maxUses: config.maxUses,
overlap: config.overlap,
};
this.initialConfig = config;
}

@@ -34,4 +47,3 @@ /**

set key(value) {
this._key = value;
this.observer.key = value;
this.setKey(value);
}

@@ -45,2 +57,15 @@ /**

}
//=========================================================================================================
// Set Key
//=========================================================================================================
/**
* @internal
* Set Key/Name of Event
* @param value - New Key/Name of Event
*/
setKey(value) {
this._key = value;
this.observer._key = value;
return this;
}
on(keyOrCallback, callback) {

@@ -60,3 +85,3 @@ const generateKey = internal_1.isFunction(keyOrCallback);

if (!internal_1.isFunction(_callback)) {
console.error("Agile: A Event Callback Function has to be an function!");
internal_1.Agile.logger.error("A Event Callback Function has to be typeof Function!");
return this;

@@ -66,3 +91,3 @@ }

if (this.callbacks[key]) {
console.error(`Agile: Event Callback Function with the key/name ${key} already exists!`);
internal_1.Agile.logger.error(`Event Callback Function with the key/name '${key}' already exists!`);
return this;

@@ -78,13 +103,13 @@ }

* @public
* Triggers Event
* -> Calls all registered Callback Functions
* Triggers Events
* @param payload - Payload that gets passed into the Callback Functions
* @param keys - Keys of Callback Functions that get triggered (Note: if not passed all registered Events will be triggered)
*/
trigger(payload) {
trigger(payload, keys) {
if (!this.enabled)
return this;
if (this.config.delay)
this.delayedTrigger(payload);
this.delayedTrigger(payload, this.config.delay, keys);
else
this.normalTrigger(payload);
this.normalTrigger(payload, keys);
return this;

@@ -122,6 +147,8 @@ }

reset() {
this.enabled = this.config.enabled || true;
this.enabled = this.initialConfig.enabled;
this.uses = 0;
if (this.currentTimeout)
if (this.currentTimeout) {
clearTimeout(this.currentTimeout);
this.currentTimeout = undefined;
}
return this;

@@ -146,8 +173,16 @@ }

* @internal
* Triggers Event
* Triggers normal Event
* @param payload - Payload that gets passed into the Callback Functions
* @param keys - Keys of Callback Functions that get triggered (Note: if not passed all registered Events will be triggered)
*/
normalTrigger(payload) {
// Call registered Callbacks
for (let key in this.callbacks)
this.callbacks[key](payload);
normalTrigger(payload, keys) {
// Call wished Callback Functions
if (!keys) {
for (let key in this.callbacks)
this.callbacks[key](payload);
}
else {
for (let key of keys)
this.callbacks[key](payload);
}
// Cause rerender

@@ -166,21 +201,35 @@ if (this.config.rerender)

* @internal
* Triggers Event with some delay (config.delay)
* Triggers async Event (Events with a delay)
* @param payload - Payload that gets passed into the Callback Functions
* @param delay - Delay until Events get triggered
* @param keys - Keys of Callback Functions that get triggered (Note: if not passed all registered Events will be triggered)
*/
delayedTrigger(payload) {
// Check if a Timeout is currently active if so add payload to queue
delayedTrigger(payload, delay, keys) {
const eventJob = new internal_1.EventJob(payload, keys);
// Execute Event no matter if another event is currently active
if (this.config.overlap) {
setTimeout(() => {
this.normalTrigger(eventJob.payload, eventJob.keys);
}, delay);
return;
}
// Check if a Event(Timeout) is currently active if so add EventJob to queue
if (this.currentTimeout !== undefined) {
if (payload)
this.queue.push(payload);
this.queue.push(eventJob);
return;
}
// Triggers Callback Functions and calls itself again if queue isn't empty
const looper = (payload) => {
// Executes EventJob and calls itself again if queue isn't empty to execute the next EventJob
const looper = (eventJob) => {
this.currentTimeout = setTimeout(() => {
this.currentTimeout = undefined;
this.normalTrigger(payload);
if (this.queue.length > 0)
looper(this.queue.shift());
}, this.config.delay);
this.normalTrigger(eventJob.payload, eventJob.keys);
if (this.queue.length > 0) {
const nextEventJob = this.queue.shift();
if (nextEventJob)
looper(nextEventJob);
}
}, delay);
};
looper(payload);
looper(eventJob);
return;

@@ -187,0 +236,0 @@ }

import { Agile } from "./internal";
export * from "./internal";
export default Agile;

@@ -0,0 +0,0 @@ "use strict";

@@ -13,12 +13,12 @@ import { Agile, Integration } from "../internal";

* @internal
* Integrates Framework (Integration) into Agile
* @param integration - Integration that gets registered/integrated
* Integrates Framework(Integration) into Agile
* @param integration - Integration/Framework that gets integrated
*/
integrate(integration: Integration): Promise<void>;
integrate(integration: Integration): Promise<boolean>;
/**
* @internal
* Updates Integrations
* -> calls 'updateMethod' in registered Integrations
* Updates registered and ready Integrations
* -> calls 'updateMethod' in all registered and ready Integrations
* @param componentInstance - Component that gets updated
* @param updatedData - Updated Properties with new Value (Note: properties with no value won't get passed)
* @param updatedData - Properties that differ from the last Value
*/

@@ -28,5 +28,5 @@ update(componentInstance: any, updatedData: Object): void;

* @internal
* Checks if Agile has registered any Integration
* Check if at least one Integration got registered
*/
hasIntegration(): boolean;
}

@@ -31,21 +31,23 @@ "use strict";

* @internal
* Integrates Framework (Integration) into Agile
* @param integration - Integration that gets registered/integrated
* Integrates Framework(Integration) into Agile
* @param integration - Integration/Framework that gets integrated
*/
integrate(integration) {
return __awaiter(this, void 0, void 0, function* () {
// Check if integration is valid
if (!integration.config.name) {
console.error("Agile: Failed to integrate framework!");
return;
// Check if Integration is valid
if (!integration._key) {
internal_1.Agile.logger.error("Failed to integrate framework! Invalid Integration!", integration._key);
return false;
}
// Integrate Integration/Framework
this.integrations.add(integration);
if (integration.config.bind)
integration.ready = yield integration.config.bind(this.agileInstance());
// Bind Framework to Agile
if (integration.methods.bind)
integration.ready = yield integration.methods.bind(this.agileInstance());
else
integration.ready = true;
// Integrate Framework
this.integrations.add(integration);
integration.integrated = true;
// Logging
if (this.agileInstance().config.logJobs)
console.log(`Agile: Successfully integrated '${integration.config.name}'`);
internal_1.Agile.logger.info(`Successfully integrated '${integration._key}'`);
return true;
});

@@ -58,16 +60,15 @@ }

* @internal
* Updates Integrations
* -> calls 'updateMethod' in registered Integrations
* Updates registered and ready Integrations
* -> calls 'updateMethod' in all registered and ready Integrations
* @param componentInstance - Component that gets updated
* @param updatedData - Updated Properties with new Value (Note: properties with no value won't get passed)
* @param updatedData - Properties that differ from the last Value
*/
update(componentInstance, updatedData) {
this.integrations.forEach((integration) => {
// Check if integration is ready
if (!integration.ready) {
console.log(`Agile: Integration '${integration.config.name}' isn't ready yet!`);
internal_1.Agile.logger.warn(`Integration '${integration.key}' isn't ready yet!`);
return;
}
if (integration.config.updateMethod)
integration.config.updateMethod(componentInstance, updatedData);
if (integration.methods.updateMethod)
integration.methods.updateMethod(componentInstance, updatedData);
});

@@ -80,3 +81,3 @@ }

* @internal
* Checks if Agile has registered any Integration
* Check if at least one Integration got registered
*/

@@ -83,0 +84,0 @@ hasIntegration() {

import { Agile } from "../internal";
export declare class Integration<F = any> {
export declare class Integration<F = any, C = any> {
_key: IntegrationKey;
frameworkInstance?: F;
ready: boolean;
config: IntegrationConfig<F>;
integrated: boolean;
methods: IntegrationMethods<C>;
/**
* @public
* Integration - Represents an Integration of Agile
* Integration - Represents a Framework/Integration of Agile
* @param config - Config
*/
constructor(config: IntegrationConfig);
constructor(config: CreateIntegrationConfig<F, C>);
/**
* @public
* Set Value of Integration
*/
set key(key: IntegrationKey);
/**
* @public
* Get Value of Integration
*/
get key(): IntegrationKey;
}
/**
* @param name - Name of Integration
* @param frameworkInstance - An Instance of the Framework which gets integrated (for instance in case of react you pass React)
* @param bind - Will be called if the framework got successful integrated
* @param updateMethod - Will be called if a Observer updates his subs (Only by Component based Subscription)
* @param key - Key/Name of Integration
* @param frameworkInstance - An Instance of the Framework that this Integration represents (for instance React)
*/
export interface IntegrationConfig<F = any> {
name?: string;
export interface CreateIntegrationConfig<F = any, C = any> extends IntegrationMethods<C> {
key: string;
frameworkInstance?: F;
bind?: (agileInstance: Agile) => boolean;
updateMethod?: (componentInstance: any, updatedData: Object) => void;
}
/**
* @param bind - Binds the Framework/Integration to Agile | Will be called after a successful integration
* @param updateMethod - Will be called if a Observer updates his subs (Only in Component based Subscriptions!)
*/
export interface IntegrationMethods<C = any> {
bind?: (agileInstance: Agile) => Promise<boolean>;
updateMethod?: (componentInstance: C, updatedData: Object) => void;
}
export declare type IntegrationKey = string | number;

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

* @public
* Integration - Represents an Integration of Agile
* Integration - Represents a Framework/Integration of Agile
* @param config - Config

@@ -13,5 +13,25 @@ */

this.ready = false;
this.config = config;
this.integrated = false;
this._key = config.key;
this.frameworkInstance = config.frameworkInstance;
this.methods = {
bind: config.bind,
updateMethod: config.updateMethod,
};
}
/**
* @public
* Set Value of Integration
*/
set key(key) {
this._key = key;
}
/**
* @public
* Get Value of Integration
*/
get key() {
return this._key;
}
}
exports.Integration = Integration;

@@ -0,15 +1,20 @@

export * from "./logger";
export * from "./utils";
export * from "./agile";
export * from "./runtime";
export * from "./runtime/observer";
export * from "./runtime/job";
export * from "./runtime/runtime.job";
export * from "./runtime/subscription/container/SubscriptionContainer";
export * from "./runtime/subscription/container/CallbackSubscriptionContainer";
export * from "./runtime/subscription/container/ComponentSubscriptionContainer";
export * from "./runtime/subscription/sub";
export * from "./storage";
export * from "./storage/persistent";
export * from "./runtime/subscription/sub.controller";
export * from "./storages";
export * from "./storages/storage";
export * from "./storages/persistent";
export * from "./state";
export * from "./state/state.observer";
export * from "./state/state.persistent";
export { Computed } from "./computed";
export * from "./state/state.runtime.job";
export * from "./computed";
export * from "./computed/computed.tracker";
export * from "./collection";

@@ -21,4 +26,5 @@ export * from "./collection/group";

export * from "./event";
export * from "./event/event.job";
export * from "./event/event.observer";
export * from "./integrations";
export * from "./integrations/integration";
export * from "./utils";

@@ -17,2 +17,6 @@ "use strict";

// !! All internal Agile modules must be imported from here!!
// Logger
__exportStar(require("./logger"), exports);
// Utils
__exportStar(require("./utils"), exports);
// Agile

@@ -23,10 +27,11 @@ __exportStar(require("./agile"), exports);

__exportStar(require("./runtime/observer"), exports);
__exportStar(require("./runtime/job"), exports);
__exportStar(require("./runtime/runtime.job"), exports);
__exportStar(require("./runtime/subscription/container/SubscriptionContainer"), exports);
__exportStar(require("./runtime/subscription/container/CallbackSubscriptionContainer"), exports);
__exportStar(require("./runtime/subscription/container/ComponentSubscriptionContainer"), exports);
__exportStar(require("./runtime/subscription/sub"), exports);
__exportStar(require("./runtime/subscription/sub.controller"), exports);
// Storage
__exportStar(require("./storage"), exports);
__exportStar(require("./storage/persistent"), exports);
__exportStar(require("./storages"), exports);
__exportStar(require("./storages/storage"), exports);
__exportStar(require("./storages/persistent"), exports);
// State

@@ -36,5 +41,6 @@ __exportStar(require("./state"), exports);

__exportStar(require("./state/state.persistent"), exports);
__exportStar(require("./state/state.runtime.job"), exports);
// Computed
var computed_1 = require("./computed");
Object.defineProperty(exports, "Computed", { enumerable: true, get: function () { return computed_1.Computed; } });
__exportStar(require("./computed"), exports);
__exportStar(require("./computed/computed.tracker"), exports);
// Collection

@@ -48,6 +54,6 @@ __exportStar(require("./collection"), exports);

__exportStar(require("./event"), exports);
__exportStar(require("./event/event.job"), exports);
__exportStar(require("./event/event.observer"), exports);
// Integrations
__exportStar(require("./integrations"), exports);
__exportStar(require("./integrations/integration"), exports);
// Utils
__exportStar(require("./utils"), exports);

@@ -1,10 +0,8 @@

import { Agile, SubscriptionContainer, Observer, Job, JobConfigInterface } from "../internal";
import { Agile, SubscriptionContainer, RuntimeJob } from "../internal";
export declare class Runtime {
agileInstance: () => Agile;
private currentJob;
private jobQueue;
private notReadyJobsToRerender;
private jobsToRerender;
trackObservers: boolean;
foundObservers: Set<Observer>;
currentJob: RuntimeJob | null;
jobQueue: Array<RuntimeJob>;
notReadyJobsToRerender: Set<RuntimeJob>;
jobsToRerender: Array<RuntimeJob>;
/**

@@ -18,14 +16,13 @@ * @internal

* @internal
* Ingests Observer into Runtime
* -> Creates Job which will be performed by the Runtime
* @param observer - Observer that gets performed by the Runtime
* Ingests Job into Runtime that gets performed
* @param job - Job
* @param config - Config
*/
ingest(observer: Observer, config: JobConfigInterface): void;
ingest(job: RuntimeJob, config?: IngestConfigInterface): void;
/**
* @internal
* Performs Job and adds him to the rerender queue if necessary
* Performs Job and adds it to the rerender queue if necessary
* @param job - Job that gets performed
*/
private perform;
perform(job: RuntimeJob): void;
/**

@@ -35,14 +32,14 @@ * @internal

*/
private updateSubscribers;
updateSubscribers(): boolean;
/**
* @internal
* Finds updated Key of SubscriptionContainer and adds it to 'changedObjectKeys'
* Finds key of Observer (Job) in subsObject and adds it to 'changedObjectKeys'
* @param subscriptionContainer - Object based SubscriptionContainer
* @param job - Job that holds the SubscriptionContainer
* @param job - Job that holds the searched Observer
*/
handleObjectBasedSubscription(subscriptionContainer: SubscriptionContainer, job: Job): void;
handleObjectBasedSubscription(subscriptionContainer: SubscriptionContainer, job: RuntimeJob): void;
/**
* @internal
* Builds Object from 'changedObjectKeys' with new Values provided by Observers
* @param subscriptionContainer - SubscriptionContainer from which the Object gets built
* Builds Object out of changedObjectKeys with Observer Value
* @param subscriptionContainer - Object based SubscriptionContainer
*/

@@ -52,7 +49,8 @@ getObjectBasedProps(subscriptionContainer: SubscriptionContainer): {

};
/**
* @internal
* Returns tracked Observers and stops Runtime from tracking anymore Observers
*/
getTrackedObservers(): Set<Observer>;
}
/**
* @param perform - If Job gets performed immediately
*/
export interface IngestConfigInterface {
perform?: boolean;
}

@@ -15,7 +15,4 @@ "use strict";

this.jobQueue = [];
this.notReadyJobsToRerender = []; // Jobs that are performed but not ready to rerender (wait for mount)
this.notReadyJobsToRerender = new Set(); // Jobs that got performed but aren't ready to get rerendered (wait for mount)
this.jobsToRerender = []; // Jobs that are performed and will be rendered
// Tracking - Used to track computed dependencies
this.trackObservers = false; // Check if Runtime have to track Observers
this.foundObservers = new Set(); // Observers that got tracked during the 'trackObservers' time
this.agileInstance = () => agileInstance;

@@ -28,23 +25,13 @@ }

* @internal
* Ingests Observer into Runtime
* -> Creates Job which will be performed by the Runtime
* @param observer - Observer that gets performed by the Runtime
* Ingests Job into Runtime that gets performed
* @param job - Job
* @param config - Config
*/
ingest(observer, config) {
ingest(job, config = {}) {
config = internal_1.defineConfig(config, {
perform: true,
background: false,
sideEffects: true,
});
const job = new internal_1.Job(observer, {
background: config.background,
sideEffects: config.sideEffects,
storage: config.storage,
});
this.jobQueue.push(job);
// Logging
if (this.agileInstance().config.logJobs)
console.log(`Agile: Created Job(${job.observer.key})`, job);
// Add Job to JobQueue (-> no Job get missing)
this.jobQueue.push(job);
internal_1.Agile.logger.if.tag(["runtime"]).info(`Created Job '${job._key}'`, job);
// Perform Job

@@ -62,3 +49,3 @@ if (config.perform) {

* @internal
* Performs Job and adds him to the rerender queue if necessary
* Performs Job and adds it to the rerender queue if necessary
* @param job - Job that gets performed

@@ -75,5 +62,4 @@ */

// Logging
if (this.agileInstance().config.logJobs)
console.log(`Agile: Completed Job(${job.observer.key})`, job);
// Perform Jobs as long as Jobs are in queue, if no job left update/rerender Subscribers of performed Jobs
internal_1.Agile.logger.if.tag(["runtime"]).info(`Completed Job '${job._key}'`, job);
// Perform Jobs as long as Jobs are left in queue, if no job left update/rerender Subscribers of jobsToRerender
if (this.jobQueue.length > 0) {

@@ -101,31 +87,37 @@ const performJob = this.jobQueue.shift();

updateSubscribers() {
if (!this.agileInstance().integrations.hasIntegration()) {
if (!this.agileInstance().hasIntegration()) {
this.jobsToRerender = [];
return;
this.notReadyJobsToRerender = new Set();
return false;
}
if (this.jobsToRerender.length <= 0)
return;
// Subscriptions that has to be updated/rerendered (Set = For preventing double subscriptions without further checks)
if (this.jobsToRerender.length <= 0 &&
this.notReadyJobsToRerender.size <= 0)
return false;
// Subscriptions that has to be updated/rerendered
const subscriptionsToUpdate = new Set();
// Handle Object based Jobs and check if Job is ready
this.jobsToRerender.concat(this.notReadyJobsToRerender).forEach((job) => {
job.observer.subs.forEach((subscriptionContainer) => {
// Check if Subscription is ready to rerender
// Build final jobsToRerender and reset jobsToRerender Instances
const jobsToRerender = this.jobsToRerender.concat(Array.from(this.notReadyJobsToRerender));
this.notReadyJobsToRerender = new Set();
this.jobsToRerender = [];
// Check if Job Subscriptions are ready and add them to subscriptionsToUpdate
jobsToRerender.forEach((job) => {
job.subscriptionContainersToUpdate.forEach((subscriptionContainer) => {
if (!subscriptionContainer.ready) {
this.notReadyJobsToRerender.push(job);
if (this.agileInstance().config.logJobs)
console.warn("Agile: SubscriptionContainer/Component isn't ready to rerender!", subscriptionContainer);
this.notReadyJobsToRerender.add(job);
// Logging
internal_1.Agile.logger.warn("SubscriptionContainer/Component isn't ready to rerender!", subscriptionContainer);
return;
}
// Handle Object based Subscription
if (subscriptionContainer.isObjectBased)
this.handleObjectBasedSubscription(subscriptionContainer, job);
subscriptionsToUpdate.add(subscriptionContainer);
job.subscriptionContainersToUpdate.delete(subscriptionContainer);
});
});
// Update Subscriptions that has to be updated/rerendered
subscriptionsToUpdate.forEach((subscriptionContainer) => {
// Call callback function if Callback based Subscription
// Call 'callback function' if Callback based Subscription
if (subscriptionContainer instanceof internal_1.CallbackSubscriptionContainer)
subscriptionContainer.callback();
// Call update method if Component based Subscription
// Call 'update method' if Component based Subscription
if (subscriptionContainer instanceof internal_1.ComponentSubscriptionContainer)

@@ -135,5 +127,6 @@ this.agileInstance().integrations.update(subscriptionContainer.component, this.getObjectBasedProps(subscriptionContainer));

// Logging
if (this.agileInstance().config.logJobs)
console.log("Agile: Updated/Rerendered Subscriptions ", subscriptionsToUpdate);
this.jobsToRerender = [];
internal_1.Agile.logger.if
.tag(["runtime"])
.info("Updated/Rerendered Subscriptions", subscriptionsToUpdate);
return true;
}

@@ -145,17 +138,17 @@ //=========================================================================================================

* @internal
* Finds updated Key of SubscriptionContainer and adds it to 'changedObjectKeys'
* Finds key of Observer (Job) in subsObject and adds it to 'changedObjectKeys'
* @param subscriptionContainer - Object based SubscriptionContainer
* @param job - Job that holds the SubscriptionContainer
* @param job - Job that holds the searched Observer
*/
handleObjectBasedSubscription(subscriptionContainer, job) {
let localKey = null;
let foundKey = null;
// Check if SubscriptionContainer is Object based
if (!subscriptionContainer.isObjectBased)
return;
// Find localKey of Job Observer in SubscriptionContainer
// Find Key of Job Observer in SubscriptionContainer
for (let key in subscriptionContainer.subsObject)
if (subscriptionContainer.subsObject[key] === job.observer)
localKey = key;
// Add localKey to changedObjectKeys
if (localKey)
subscriptionContainer.changedObjectKeys.push(localKey);
foundKey = key;
if (foundKey)
subscriptionContainer.observerKeysToUpdate.push(foundKey);
}

@@ -167,33 +160,18 @@ //=========================================================================================================

* @internal
* Builds Object from 'changedObjectKeys' with new Values provided by Observers
* @param subscriptionContainer - SubscriptionContainer from which the Object gets built
* Builds Object out of changedObjectKeys with Observer Value
* @param subscriptionContainer - Object based SubscriptionContainer
*/
getObjectBasedProps(subscriptionContainer) {
const finalObject = {};
// Map trough changed Keys and build finalObject
subscriptionContainer.changedObjectKeys.forEach((changedKey) => {
// Check if Observer at changedKey has value property, if so add it to final Object
const props = {};
// Map trough observerKeysToUpdate and build object out of Observer value
subscriptionContainer.observerKeysToUpdate.forEach((updatedKey) => {
if (subscriptionContainer.subsObject &&
subscriptionContainer.subsObject[changedKey]["value"])
finalObject[changedKey] =
subscriptionContainer.subsObject[changedKey]["value"];
subscriptionContainer.subsObject[updatedKey]["value"])
props[updatedKey] =
subscriptionContainer.subsObject[updatedKey]["value"];
});
subscriptionContainer.changedObjectKeys = [];
return finalObject;
subscriptionContainer.observerKeysToUpdate = [];
return props;
}
//=========================================================================================================
// Get Tracked Observers
//=========================================================================================================
/**
* @internal
* Returns tracked Observers and stops Runtime from tracking anymore Observers
*/
getTrackedObservers() {
const finalFoundObservers = this.foundObservers;
// Reset tracking
this.trackObservers = false;
this.foundObservers = new Set();
return finalFoundObservers;
}
}
exports.Runtime = Runtime;

@@ -1,2 +0,2 @@

import { Agile, StateKey, Job, SubscriptionContainer } from "../internal";
import { Agile, StateKey, RuntimeJob, SubscriptionContainer } from "../internal";
export declare type ObserverKey = string | number;

@@ -12,8 +12,7 @@ export declare class Observer<ValueType = any> {

* Observer - Handles subscriptions and dependencies of an Agile Class and is like an instance to the Runtime
* Note: No stand alone class!!
* @param agileInstance - An instance of Agile
* @param value - Initial Value of Observer
* @param deps - Initial Dependencies of Observer
* @param key - Key/Name of Observer
* @param config - Config
*/
constructor(agileInstance: Agile, deps?: Array<Observer>, key?: ObserverKey, value?: ValueType);
constructor(agileInstance: Agile, config?: CreateObserverConfigInterface<ValueType>);
/**

@@ -34,3 +33,3 @@ * @internal

*/
perform(job: Job): void;
perform(job: RuntimeJob): void;
/**

@@ -55,1 +54,13 @@ * @internal

}
/**
* @param deps - Initial Dependencies of Observer
* @param subs - Initial Subscriptions of Observer
* @param key - Key/Name of Observer
* @param value - Initial Value of Observer
*/
export interface CreateObserverConfigInterface<ValueType = any> {
deps?: Array<Observer>;
subs?: Array<SubscriptionContainer>;
key?: ObserverKey;
value?: ValueType;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Observer = void 0;
const internal_1 = require("../internal");
class Observer {

@@ -8,14 +9,19 @@ /**

* Observer - Handles subscriptions and dependencies of an Agile Class and is like an instance to the Runtime
* Note: No stand alone class!!
* @param agileInstance - An instance of Agile
* @param value - Initial Value of Observer
* @param deps - Initial Dependencies of Observer
* @param key - Key/Name of Observer
* @param config - Config
*/
constructor(agileInstance, deps, key, value) {
constructor(agileInstance, config = {}) {
var _a, _b;
this.deps = new Set(); // Observers that depends on this Observer
this.subs = new Set(); // SubscriptionContainers(Components) which this Observer has subscribed
this.subs = new Set(); // SubscriptionContainers (Components) that this Observer has subscribed
config = internal_1.defineConfig(config, {
deps: [],
subs: [],
});
this.agileInstance = () => agileInstance;
this._key = key;
this.value = value;
deps === null || deps === void 0 ? void 0 : deps.forEach((observer) => this.deps.add(observer));
this._key = config.key;
this.value = config.value;
(_a = config.deps) === null || _a === void 0 ? void 0 : _a.forEach((observer) => this.depend(observer));
(_b = config.subs) === null || _b === void 0 ? void 0 : _b.forEach((subscriptionContainer) => this.subscribe(subscriptionContainer));
}

@@ -45,3 +51,3 @@ /**

perform(job) {
console.warn("Agile: Didn't set perform function in Observer ", this.key);
internal_1.Agile.logger.warn("Perform function isn't Set in Observer! Be aware that Observer is no stand alone class!");
}

@@ -69,4 +75,7 @@ //=========================================================================================================

subscribe(subscriptionContainer) {
if (!this.subs.has(subscriptionContainer))
if (!this.subs.has(subscriptionContainer)) {
this.subs.add(subscriptionContainer);
// Add this to subscriptionContainer to keep track of the Observers the subscriptionContainer hold
subscriptionContainer.subs.add(this);
}
}

@@ -82,6 +91,8 @@ //=========================================================================================================

unsubscribe(subscriptionContainer) {
if (this.subs.has(subscriptionContainer))
if (this.subs.has(subscriptionContainer)) {
this.subs.delete(subscriptionContainer);
subscriptionContainer.subs.delete(this);
}
}
}
exports.Observer = Observer;

@@ -1,2 +0,2 @@

import { Observer, SubscriptionContainer } from "../../../internal";
import { Observer, SubscriptionContainer, SubscriptionContainerKeyType } from "../../../internal";
export declare class CallbackSubscriptionContainer extends SubscriptionContainer {

@@ -9,4 +9,5 @@ callback: Function;

* @param subs - Initial Subscriptions
* @param key - Key/Name of Callback Subscription Container
*/
constructor(callback: Function, subs?: Set<Observer>);
constructor(callback: Function, subs?: Array<Observer>, key?: SubscriptionContainerKeyType);
}

@@ -11,5 +11,6 @@ "use strict";

* @param subs - Initial Subscriptions
* @param key - Key/Name of Callback Subscription Container
*/
constructor(callback, subs) {
super(subs);
constructor(callback, subs = [], key) {
super(subs, key);
this.callback = callback;

@@ -16,0 +17,0 @@ }

@@ -1,2 +0,2 @@

import { Observer, SubscriptionContainer } from "../../../internal";
import { Observer, SubscriptionContainer, SubscriptionContainerKeyType } from "../../../internal";
export declare class ComponentSubscriptionContainer extends SubscriptionContainer {

@@ -9,4 +9,5 @@ component: any;

* @param subs - Initial Subscriptions
* @param key - Key/Name of Component Subscription Container
*/
constructor(component: any, subs?: Set<Observer>);
constructor(component: any, subs?: Array<Observer>, key?: SubscriptionContainerKeyType);
}

@@ -11,5 +11,6 @@ "use strict";

* @param subs - Initial Subscriptions
* @param key - Key/Name of Component Subscription Container
*/
constructor(component, subs) {
super(subs);
constructor(component, subs = [], key) {
super(subs, key);
this.component = component;

@@ -16,0 +17,0 @@ }

import { Observer } from "../../../internal";
export declare class SubscriptionContainer {
key?: SubscriptionContainerKeyType;
ready: boolean;
subs: Set<Observer>;
isObjectBased: boolean;
changedObjectKeys: Array<string>;
observerKeysToUpdate: Array<string>;
subsObject?: {

@@ -15,4 +16,6 @@ [key: string]: Observer;

* @param subs - Initial Subscriptions
* @param key - Key/Name of Subscription Container
*/
constructor(subs?: Set<Observer>);
constructor(subs?: Array<Observer>, key?: SubscriptionContainerKeyType);
}
export declare type SubscriptionContainerKeyType = string | number;

@@ -10,13 +10,13 @@ "use strict";

* @param subs - Initial Subscriptions
* @param key - Key/Name of Subscription Container
*/
constructor(subs) {
constructor(subs = [], key) {
this.ready = false;
this.subs = new Set([]); // Observers that are Subscribed to this SubscriptionContainer (Component)
// For Object based Subscription
this.isObjectBased = false;
this.changedObjectKeys = []; // Holds temporary changed Object Keys (Runtime)
if (subs)
this.subs = subs;
this.observerKeysToUpdate = []; // Holds temporary keys of Observers that got updated (Note: keys based on 'subsObject')
this.subs = new Set(subs);
this.key = key;
}
}
exports.SubscriptionContainer = SubscriptionContainer;

@@ -1,2 +0,2 @@

import { Agile, StorageKey, StateObserver, StatePersistent, Observer, StateJobConfigInterface, StatePersistentConfigInterface } from "../internal";
import { Agile, StorageKey, StateObserver, StatePersistent, Observer, PersistentKey, StateIngestConfigInterface, StateRuntimeJobConfigInterface } from "../internal";
export declare class State<ValueType = any> {

@@ -12,3 +12,3 @@ agileInstance: () => Agile;

nextStateValue: ValueType;
observer: StateObserver;
observer: StateObserver<ValueType>;
sideEffects: {

@@ -19,6 +19,7 @@ [key: string]: (properties?: {

};
computeMethod?: ComputeMethod<ValueType>;
isPersisted: boolean;
persistent: StatePersistent | undefined;
watchers: {
[key: string]: (value: any) => void;
[key: string]: StateWatcherCallback<ValueType>;
};

@@ -30,6 +31,5 @@ /**

* @param initialValue - Initial Value of State
* @param key - Key/Name of State
* @param deps - Initial deps of State
* @param config - Config
*/
constructor(agileInstance: Agile, initialValue: ValueType, key?: StateKey, deps?: Array<Observer>);
constructor(agileInstance: Agile, initialValue: ValueType, config?: StateConfigInterface);
/**

@@ -57,7 +57,6 @@ * @public

* @internal
* Set Key/Name of State
* https://github.com/microsoft/TypeScript/issues/338
* Updates Key/Name of State
* @param value - New Key/Name of State
*/
setKey(value: StateKey | undefined): void;
setKey(value: StateKey | undefined): this;
/**

@@ -69,3 +68,3 @@ * @public

*/
set(value: ValueType, config?: SetConfigInterface): this;
set(value: ValueType, config?: StateRuntimeJobConfigInterface): this;
/**

@@ -76,3 +75,3 @@ * @internal

*/
ingest(config?: StateJobConfigInterface): this;
ingest(config?: StateIngestConfigInterface): this;
/**

@@ -88,9 +87,11 @@ * @public

* Undoes latest State Value change
* @param config - Config
*/
undo(): void;
undo(config?: StateRuntimeJobConfigInterface): this;
/**
* @public
* Resets State to its initial Value
* @param config - Config
*/
reset(): this;
reset(config?: StateRuntimeJobConfigInterface): this;
/**

@@ -110,10 +111,10 @@ * @public

*/
watch(callback: Callback<ValueType>): string;
watch(callback: StateWatcherCallback<ValueType>): string;
/**
* @public
* Watches State and detects State changes
* @param key - Key of Watcher Function
* @param key - Key/Name of Watcher Function
* @param callback - Callback Function that gets called if the State Value changes
*/
watch(key: string, callback: Callback<ValueType>): this;
watch(key: string, callback: StateWatcherCallback<ValueType>): this;
/**

@@ -130,7 +131,7 @@ * @public

*/
onInaugurated(callback: Callback<ValueType>): void;
onInaugurated(callback: StateWatcherCallback<ValueType>): void;
/**
* @public
* Checks if watcher at given Key exists
* @param key - Key of Watcher
* @param key - Key/Name of Watcher
*/

@@ -147,8 +148,15 @@ hasWatcher(key: string): boolean;

* Stores State Value into Agile Storage permanently
* @param key - Storage Key (Note: not needed if State has key/name)
* @param key - Key/Name of created Persistent (Note: Key required if State has no set Key!)
* @param config - Config
*/
persist(key?: StorageKey, config?: StatePersistentConfigInterface): this;
persist(key?: PersistentKey, config?: StatePersistentConfigInterface): this;
/**
* @public
* Callback Function that gets called if the persisted Value gets loaded into the State for the first Time
* Note: Only useful for persisted States!
* @param callback - Callback Function
*/
onLoad(callback: (success: boolean) => void): this;
/**
* @public
* Creates fresh copy of State Value (-> No reference to State Value)

@@ -181,5 +189,11 @@ */

/**
* @public
* Function that recomputes State Value if it changes
* @param method - Computed Function
*/
compute(method: ComputeMethod<ValueType>): this;
/**
* @internal
* Adds SideEffect to State
* @param key - Key of SideEffect
* @param key - Key/Name of SideEffect
* @param sideEffect - Callback Function that gets called on every State Value change

@@ -205,5 +219,6 @@ */

* Checks if Value has correct valueType (js)
* Note: If no valueType set, it returns true
* @param value - Value that gets checked for its correct Type
*/
private hasCorrectType;
hasCorrectType(value: any): boolean;
/**

@@ -222,19 +237,26 @@ * @internal

/**
* @param background - If assigning a new value happens in the background (-> not causing any rerender)
* @param sideEffects - If Side Effects of State get executed
* @param storage - If State value gets saved in Agile Storage (only useful if State is persisted)
* @param key - Key/Name of State
* @param deps - Initial deps of State
* @param isPlaceholder - If State is initially a Placeholder
*/
export interface SetConfigInterface {
background?: boolean;
sideEffects?: boolean;
storage?: boolean;
export interface StateConfigInterface {
key?: StateKey;
deps?: Array<Observer>;
isPlaceholder?: boolean;
}
/**
* @param background - If assigning new value happens in the background (-> not causing any rerender)
* @param addNewProperties - If new Properties gets added to the State Value
*/
export interface PatchConfigInterface {
export interface PatchConfigInterface extends StateRuntimeJobConfigInterface {
addNewProperties?: boolean;
background?: boolean;
}
export declare type Callback<T = any> = (value: T) => void;
/**
* @param instantiate - If Persistent gets instantiated
* @param storageKeys - Key/Name of Storages which gets used to persist the State Value (NOTE: If not passed the default Storage will be used)
*/
export interface StatePersistentConfigInterface {
instantiate?: boolean;
storageKeys?: StorageKey[];
}
export declare type StateWatcherCallback<T = any> = (value: T) => void;
export declare type ComputeMethod<T = any> = (value: T) => T;

@@ -11,18 +11,28 @@ "use strict";

* @param initialValue - Initial Value of State
* @param key - Key/Name of State
* @param deps - Initial deps of State
* @param config - Config
*/
constructor(agileInstance, initialValue, key, deps = []) {
constructor(agileInstance, initialValue, config = {}) {
this.isSet = false; // If value is not the same as initialValue
this.isPlaceholder = false;
this.sideEffects = {}; // SideEffects of State (will be executed in Runtime)
this.isPersisted = false; // If State is stored in Storage
this.isPersisted = false; // If State can be stored in Agile Storage (-> successfully integrated persistent)
this.watchers = {};
config = internal_1.defineConfig(config, {
deps: [],
isPlaceholder: false,
});
this.agileInstance = () => agileInstance;
this.initialStateValue = initialValue;
this._key = key;
this._key = config.key;
this.observer = new internal_1.StateObserver(this, {
key: config.key,
deps: config.deps,
});
this.initialStateValue = internal_1.copy(initialValue);
this._value = internal_1.copy(initialValue);
this.previousStateValue = internal_1.copy(initialValue);
this.nextStateValue = internal_1.copy(initialValue);
this.observer = new internal_1.StateObserver(agileInstance, this, deps, key);
this.isPlaceholder = true;
// Initial Set
if (!config.isPlaceholder)
this.set(initialValue, { overwrite: true });
}

@@ -41,5 +51,3 @@ /**

get value() {
// Add State to tracked Observers (for auto tracking used observers in computed function)
if (this.agileInstance().runtime.trackObservers)
this.agileInstance().runtime.foundObservers.add(this.observer);
internal_1.ComputedTracker.tracked(this.observer);
return this._value;

@@ -66,7 +74,7 @@ }

* @internal
* Set Key/Name of State
* https://github.com/microsoft/TypeScript/issues/338
* Updates Key/Name of State
* @param value - New Key/Name of State
*/
setKey(value) {
var _a, _b;
const oldKey = this._key;

@@ -76,8 +84,7 @@ // Update State Key

// Update Key in Observer
this.observer.key = value;
// Update Key in PersistManager
if (value !== undefined &&
this.persistent &&
this.persistent.key === oldKey)
this.persistent.key = value;
this.observer._key = value;
// Update Key in Persistent (only if oldKey equal to persistentKey -> otherwise the PersistentKey got formatted and will be set where other)
if (value && ((_a = this.persistent) === null || _a === void 0 ? void 0 : _a._key) === oldKey)
(_b = this.persistent) === null || _b === void 0 ? void 0 : _b.setKey(value);
return this;
}

@@ -97,13 +104,17 @@ //=========================================================================================================

background: false,
force: false,
storage: true,
overwrite: false,
});
// Check value has correct Type (js)
if (this.valueType && !this.hasCorrectType(value)) {
console.warn(`Agile: Incorrect type (${typeof value}) was provided.`);
return this;
if (!this.hasCorrectType(value)) {
const message = `Incorrect type (${typeof value}) was provided.`;
if (!config.force) {
internal_1.Agile.logger.error(message);
return this;
}
internal_1.Agile.logger.warn(message);
}
// Check if value has changed
if (internal_1.equal(this.nextStateValue, value))
return this;
// Ingest new value into runtime
this.observer.ingest(value, config);
// Ingest new value into Runtime
this.observer.ingestValue(value, config);
return this;

@@ -120,8 +131,3 @@ }

ingest(config = {}) {
config = internal_1.defineConfig(config, {
sideEffects: true,
background: false,
forceRerender: false,
});
this.observer.ingest(internal_1.internalIngestKey, config);
this.observer.ingest(config);
return this;

@@ -142,3 +148,3 @@ }

if (!supportedTypes.includes(type.name)) {
console.warn(`Agile: '${type}' is not supported! Supported types: String, Boolean, Array, Object, Number`);
internal_1.Agile.logger.warn(`'${type}' is not supported! Supported types: String, Boolean, Array, Object, Number`);
return this;

@@ -155,5 +161,7 @@ }

* Undoes latest State Value change
* @param config - Config
*/
undo() {
this.set(this.previousStateValue);
undo(config = {}) {
this.set(this.previousStateValue, config);
return this;
}

@@ -166,7 +174,6 @@ //=========================================================================================================

* Resets State to its initial Value
* @param config - Config
*/
reset() {
var _a;
this.set(this.initialStateValue);
(_a = this.persistent) === null || _a === void 0 ? void 0 : _a.removeValue(); // Remove State from Storage (since its the initial Value)
reset(config = {}) {
this.set(this.initialStateValue, config);
return this;

@@ -187,19 +194,26 @@ }

addNewProperties: true,
sideEffects: true,
background: false,
force: false,
storage: true,
overwrite: false,
});
if (!internal_1.isValidObject(this.nextStateValue)) {
console.warn("Agile: You can't use the patch method on a non object States!");
internal_1.Agile.logger.error("You can't use the patch method on a non object based States!");
return this;
}
if (!internal_1.isValidObject(targetWithChanges)) {
console.warn("Agile: TargetWithChanges has to be an object!");
internal_1.Agile.logger.error("TargetWithChanges has to be an Object!");
return this;
}
// Merge targetWithChanges into nextStateValue
this.nextStateValue = internal_1.flatMerge(this.nextStateValue, targetWithChanges, { addNewProperties: config.addNewProperties });
// Check if value has been changed
if (internal_1.equal(this.value, this.nextStateValue))
return this;
this.nextStateValue = internal_1.flatMerge(internal_1.copy(this.nextStateValue), targetWithChanges, { addNewProperties: config.addNewProperties });
// Ingest updated nextStateValue into Runtime
this.ingest({ background: config.background });
this.ingest({
background: config.background,
force: config.force,
overwrite: config.overwrite,
sideEffects: config.sideEffects,
storage: config.storage,
});
return this;

@@ -219,10 +233,10 @@ }

}
// Check if Callback is a Function
// Check if Callback is valid Function
if (!internal_1.isFunction(_callback)) {
console.error("Agile: A Watcher Callback Function has to be an function!");
internal_1.Agile.logger.error("A Watcher Callback Function has to be typeof Function!");
return this;
}
// Check if Callback Function already exists
// Check if watcherKey is already occupied
if (this.watchers[key]) {
console.error(`Agile: Watcher Callback Function with the key/name ${key} already exists!`);
internal_1.Agile.logger.error(`Watcher Callback Function with the key/name '${key}' already exists!`);
return this;

@@ -251,5 +265,5 @@ }

onInaugurated(callback) {
const watcherKey = "InauguratedWatcher";
this.watch(watcherKey, () => {
callback(this.getPublicValue());
const watcherKey = "InauguratedWatcherKey";
this.watch(watcherKey, (value) => {
callback(value);
this.removeWatcher(watcherKey);

@@ -264,3 +278,3 @@ });

* Checks if watcher at given Key exists
* @param key - Key of Watcher
* @param key - Key/Name of Watcher
*/

@@ -275,3 +289,3 @@ hasWatcher(key) {

_config = keyOrConfig;
key = undefined;
key = this._key;
}

@@ -284,11 +298,33 @@ else {

instantiate: true,
storageKeys: [],
});
// Update Persistent Key
if (this.persistent)
internal_1.Agile.logger.warn(`By persisting the State '${this._key}' twice you overwrite the old Persistent Instance!`);
// Create persistent -> Persist Value
this.persistent = new internal_1.StatePersistent(this, {
instantiate: _config.instantiate,
storageKeys: _config.storageKeys,
key: key,
});
return this;
}
//=========================================================================================================
// On Load
//=========================================================================================================
/**
* @public
* Callback Function that gets called if the persisted Value gets loaded into the State for the first Time
* Note: Only useful for persisted States!
* @param callback - Callback Function
*/
onLoad(callback) {
if (this.persistent) {
if (key)
this.persistent.key = key;
return this;
this.persistent.onLoad = callback;
// If State is already 'isPersisted' the loading was successful -> callback can be called
if (this.isPersisted)
callback(true);
}
// Create persistent -> Persist Value
this.persistent = new internal_1.StatePersistent(this.agileInstance(), this, key, { instantiate: _config.instantiate });
else {
internal_1.Agile.logger.error(`Please make sure you persist the State '${this._key}' before using the 'onLoad' function!`);
}
return this;

@@ -314,3 +350,3 @@ }

get exists() {
return this.getPublicValue() !== undefined && !this.isPlaceholder;
return this._value !== undefined && !this.isPlaceholder;
}

@@ -348,7 +384,24 @@ //=========================================================================================================

invert() {
if (typeof this._value !== "boolean") {
console.warn("Agile: You can only invert boolean based States!");
if (typeof this._value === "boolean") {
this.set(!this._value);
}
else {
internal_1.Agile.logger.error("You can only invert boolean based States!");
}
return this;
}
//=========================================================================================================
// Compute
//=========================================================================================================
/**
* @public
* Function that recomputes State Value if it changes
* @param method - Computed Function
*/
compute(method) {
if (!internal_1.isFunction(method)) {
internal_1.Agile.logger.error("A computeMethod has to be a function!");
return this;
}
this.set(this._value);
this.computeMethod = method;
return this;

@@ -362,3 +415,3 @@ }

* Adds SideEffect to State
* @param key - Key of SideEffect
* @param key - Key/Name of SideEffect
* @param sideEffect - Callback Function that gets called on every State Value change

@@ -368,3 +421,3 @@ */

if (!internal_1.isFunction(sideEffect)) {
console.error("Agile: A sideEffect function has to be an function!");
internal_1.Agile.logger.error("A sideEffect function has to be a function!");
return this;

@@ -404,5 +457,8 @@ }

* Checks if Value has correct valueType (js)
* Note: If no valueType set, it returns true
* @param value - Value that gets checked for its correct Type
*/
hasCorrectType(value) {
if (!this.valueType)
return true;
let type = typeof value;

@@ -432,5 +488,5 @@ return type === this.valueType;

getPersistableValue() {
return this.value;
return this._value;
}
}
exports.State = State;

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

import { Agile, Observer, State, Job, JobConfigInterface, ObserverKey } from "../internal";
export declare const internalIngestKey = "THIS_IS_AN_INTERNAL_KEY_FOR_INGESTING_INTERNAL_STUFF";
import { Observer, State, ObserverKey, SubscriptionContainer, IngestConfigInterface, StateRuntimeJob, StateRuntimeJobConfigInterface, RuntimeJobKey } from "../internal";
export declare class StateObserver<ValueType = any> extends Observer {

@@ -9,10 +8,14 @@ state: () => State<ValueType>;

* State Observer - Handles State changes, dependencies (-> Interface to Runtime)
* @param agileInstance - An instance of Agile
* @param state - State
* @param deps - Initial Dependencies of State Observer
* @param key - Key/Name of State Observer
* @param config - Config
*/
constructor(agileInstance: Agile, state: State<ValueType>, deps?: Array<Observer>, key?: ObserverKey);
constructor(state: State<ValueType>, config?: CreateStateObserverConfigInterface);
/**
* @internal
* Ingests nextStateValue or computedValue into Runtime and applies it to the State
* @param config - Config
*/
ingest(config?: StateIngestConfigInterface): void;
/**
* @internal
* Ingests new State Value into Runtime and applies it to the State

@@ -22,22 +25,31 @@ * @param newStateValue - New Value of the State

*/
ingest(newStateValue?: ValueType | InternalIngestKeyType, config?: StateJobConfigInterface): void;
ingestValue(newStateValue: ValueType, config?: StateIngestConfigInterface): void;
/**
* @internal
* Performs Job from Runtime
* @param job - Job that gets performed
* Performs Job that holds this Observer
* @param job - Job
*/
perform(job: Job<this>): void;
perform(job: StateRuntimeJob): void;
/**
* @internal
* SideEffects of Perform Function
* @param job - Job whose SideEffects gets executed
* SideEffects of Job
* @param job - Job
*/
private sideEffects;
sideEffects(job: StateRuntimeJob): void;
}
export declare type InternalIngestKeyType = "THIS_IS_AN_INTERNAL_KEY_FOR_INGESTING_INTERNAL_STUFF";
/**
* @param forceRerender - Force rerender no matter what happens
* @param deps - Initial Dependencies of State Observer
* @param subs - Initial Subscriptions of State Observer
* @param key - Key/Name of State Observer
*/
export interface StateJobConfigInterface extends JobConfigInterface {
forceRerender?: boolean;
export interface CreateStateObserverConfigInterface {
deps?: Array<Observer>;
subs?: Array<SubscriptionContainer>;
key?: ObserverKey;
}
/**
* @param key - Key/Name of Job that gets created
*/
export interface StateIngestConfigInterface extends StateRuntimeJobConfigInterface, IngestConfigInterface {
key?: RuntimeJobKey;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StateObserver = exports.internalIngestKey = void 0;
exports.StateObserver = void 0;
const internal_1 = require("../internal");
exports.internalIngestKey = "THIS_IS_AN_INTERNAL_KEY_FOR_INGESTING_INTERNAL_STUFF";
class StateObserver extends internal_1.Observer {

@@ -10,11 +9,9 @@ /**

* State Observer - Handles State changes, dependencies (-> Interface to Runtime)
* @param agileInstance - An instance of Agile
* @param state - State
* @param deps - Initial Dependencies of State Observer
* @param key - Key/Name of State Observer
* @param config - Config
*/
constructor(agileInstance, state, deps, key) {
super(agileInstance, deps, key, state.value);
constructor(state, config = {}) {
super(state.agileInstance(), Object.assign(Object.assign({}, config), { value: state._value }));
this.state = () => state;
this.nextStateValue = state.value;
this.nextStateValue = internal_1.copy(state._value);
}

@@ -26,2 +23,19 @@ //=========================================================================================================

* @internal
* Ingests nextStateValue or computedValue into Runtime and applies it to the State
* @param config - Config
*/
ingest(config = {}) {
const state = this.state();
let newStateValue;
if (state instanceof internal_1.Computed)
newStateValue = state.computeValue();
else
newStateValue = state.nextStateValue;
this.ingestValue(newStateValue, config);
}
//=========================================================================================================
// Ingest Value
//=========================================================================================================
/**
* @internal
* Ingests new State Value into Runtime and applies it to the State

@@ -31,3 +45,3 @@ * @param newStateValue - New Value of the State

*/
ingest(newStateValue = exports.internalIngestKey, config = {}) {
ingestValue(newStateValue, config = {}) {
const state = this.state();

@@ -38,24 +52,30 @@ config = internal_1.defineConfig(config, {

sideEffects: true,
forceRerender: false,
force: false,
storage: true,
overwrite: false,
});
// If forceRerender, set background config to false since forceRerender is 'stronger' than background
if (config.forceRerender && config.background)
config.background = false;
// Grab nextState or compute State if internalIngestKey got passed
if (newStateValue === exports.internalIngestKey) {
if (state instanceof internal_1.Computed)
this.nextStateValue = state.computeValue();
else
this.nextStateValue = state.nextStateValue;
// Force overwriting State because if assigning Value to State, the State shouldn't be a placeholder anymore
if (state.isPlaceholder) {
config.force = true;
config.overwrite = true;
}
else
this.nextStateValue = newStateValue;
// Check if State Value and the new Value are equals (Note: Not checking state.nextStateValue because of the internalIngestKey)
if (internal_1.equal(state.value, this.nextStateValue) && !config.forceRerender) {
if (this.agileInstance().config.logJobs)
console.warn("Agile: Doesn't created job because state values are the same! ");
// Assign next State Value and compute it if necessary
this.nextStateValue = state.computeMethod
? internal_1.copy(state.computeMethod(newStateValue))
: internal_1.copy(newStateValue);
// Check if State Value and new/next Value are equals
if (internal_1.equal(state._value, this.nextStateValue) && !config.force)
return;
}
this.agileInstance().runtime.ingest(this, config);
// Create Job
const job = new internal_1.StateRuntimeJob(this, {
storage: config.storage,
sideEffects: config.sideEffects,
force: config.force,
background: config.background,
overwrite: config.overwrite,
key: config.key || this._key,
});
this.agileInstance().runtime.ingest(job, {
perform: config.perform,
});
}

@@ -67,24 +87,19 @@ //=========================================================================================================

* @internal
* Performs Job from Runtime
* @param job - Job that gets performed
* Performs Job that holds this Observer
* @param job - Job
*/
perform(job) {
var _a;
const state = job.observer.state();
// Set Previous State
state.previousStateValue = internal_1.copy(state.value);
// Set new State Value
state._value = internal_1.copy(this.nextStateValue);
state.nextStateValue = internal_1.copy(this.nextStateValue);
// Store State changes in Storage
if (job.config.storage)
(_a = state.persistent) === null || _a === void 0 ? void 0 : _a.updateValue();
// Set isSet
state.isSet = internal_1.notEqual(this.nextStateValue, state.initialStateValue);
// Reset isPlaceholder since it got an value
if (state.isPlaceholder)
// Assign new State Values
state.previousStateValue = internal_1.copy(state._value);
state._value = internal_1.copy(job.observer.nextStateValue);
state.nextStateValue = internal_1.copy(job.observer.nextStateValue);
job.observer.value = internal_1.copy(job.observer.nextStateValue);
// Overwrite old State Values
if (job.config.overwrite) {
state.initialStateValue = internal_1.copy(state._value);
state.previousStateValue = internal_1.copy(state._value);
state.isPlaceholder = false;
// Update Observer value
this.value = internal_1.copy(this.nextStateValue);
// Perform SideEffects of the Perform Function
}
state.isSet = internal_1.notEqual(state._value, state.initialStateValue);
this.sideEffects(job);

@@ -97,4 +112,4 @@ }

* @internal
* SideEffects of Perform Function
* @param job - Job whose SideEffects gets executed
* SideEffects of Job
* @param job - Job
*/

@@ -114,6 +129,5 @@ sideEffects(job) {

// Ingest Dependencies of Observer into Runtime
job.observer.deps.forEach((observer) => observer instanceof StateObserver &&
observer.ingest(exports.internalIngestKey, { perform: false }));
state.observer.deps.forEach((observer) => observer instanceof StateObserver && observer.ingest({ perform: false }));
}
}
exports.StateObserver = StateObserver;

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

import { Agile, Persistent, State, StorageKey } from "../internal";
import { CreatePersistentConfigInterface, Persistent, PersistentKey, State, StorageKey } from "../internal";
export declare class StatePersistent<ValueType = any> extends Persistent {
static storeValueSideEffectKey: string;
state: () => State;

@@ -7,46 +8,49 @@ /**

* State Persist Manager - Handles permanent storing of State Value
* @param agileInstance - An instance of Agile
* @param state - State that gets stored
* @param key - Key of Storage property
* @param config - Config
*/
constructor(agileInstance: Agile, state: State<ValueType>, key?: StorageKey, config?: StatePersistentConfigInterface);
set key(value: StorageKey);
get key(): StorageKey;
constructor(state: State<ValueType>, config?: CreatePersistentConfigInterface);
/**
* @public
* Sets Key/Name of Persistent
* @internal
* Updates Key/Name of Persistent
* @param value - New Key/Name of Persistent
*/
setKey(value: StorageKey): Promise<void>;
setKey(value?: StorageKey): Promise<void>;
/**
* @internal
* Loads Value from Storage
* Loads/Saves Storage Value for the first Time
*/
initialLoading(): Promise<void>;
/**
* @internal
* Loads State Value from the Storage
* @return Success?
*/
loadValue(): Promise<boolean>;
loadPersistedValue(key?: PersistentKey): Promise<boolean>;
/**
* @internal
* Saves/Updates Value in Storage
* Sets everything up so that the State gets saved in the Storage on every Value change
* @return Success?
*/
updateValue(): Promise<boolean>;
persistValue(key?: PersistentKey): Promise<boolean>;
/**
* @internal
* Removes Value form Storage
* Removes State Value form the Storage
* @return Success?
*/
removeValue(): Promise<boolean>;
removePersistedValue(key?: PersistentKey): Promise<boolean>;
/**
* @internal
* Validates Storage Key
* @param key - Key that gets validated
* Formats Storage Key
* @param key - Key that gets formatted
*/
validateKey(key?: StorageKey): StorageKey | null;
formatKey(key?: PersistentKey): PersistentKey | undefined;
/**
* @internal
* Rebuilds Storage depending on the State Value (Saves current State Value into the Storage)
* @param state - State that holds the new Value
* @param key - Key/Name of Persistent
* @param config - Config
*/
rebuildStorageSideEffect(state: State<ValueType>, key: PersistentKey, config?: any): void;
}
/**
* @param instantiate - If Persistent gets instantiated
*/
export interface StatePersistentConfigInterface {
instantiate?: boolean;
}

@@ -18,24 +18,22 @@ "use strict";

* State Persist Manager - Handles permanent storing of State Value
* @param agileInstance - An instance of Agile
* @param state - State that gets stored
* @param key - Key of Storage property
* @param config - Config
*/
constructor(agileInstance, state, key, config = {}) {
super(agileInstance);
constructor(state, config = {}) {
super(state.agileInstance(), {
instantiate: false,
});
config = internal_1.defineConfig(config, {
instantiate: true,
storageKeys: [],
});
this.state = () => state;
if (config.instantiate)
this.instantiatePersistent(key).then((success) => {
state.isPersisted = success;
});
this.instantiatePersistent({
key: config.key,
storageKeys: config.storageKeys,
});
// Load/Store persisted Value for the first Time
if (this.ready && config.instantiate)
this.initialLoading();
}
set key(value) {
this.setKey(value);
}
get key() {
return this._key;
}
//=========================================================================================================

@@ -45,4 +43,4 @@ // Set Key

/**
* @public
* Sets Key/Name of Persistent
* @internal
* Updates Key/Name of Persistent
* @param value - New Key/Name of Persistent

@@ -52,54 +50,83 @@ */

return __awaiter(this, void 0, void 0, function* () {
// If persistent isn't ready try to init it with the new Key
if (!this.ready) {
this.instantiatePersistent(value).then((success) => {
this.state().isPersisted = success;
});
const oldKey = this._key;
const wasReady = this.ready;
// Assign Key
if (value === this._key)
return;
this._key = value || internal_1.Persistent.placeHolderKey;
const isValid = this.validatePersistent();
// Try to Initial Load Value if persistent wasn't ready and return
if (!wasReady) {
if (isValid)
yield this.initialLoading();
return;
}
// Check if key has changed
if (value === this._key)
return;
// Remove value with old Key
yield this.removeValue();
// Update Key
this._key = value;
// Set value with new Key
yield this.updateValue();
// Remove value at old Key
yield this.removePersistedValue(oldKey);
// Assign Value to new Key
if (isValid)
yield this.persistValue(value);
});
}
//=========================================================================================================
// Load Value
// Initial Loading
//=========================================================================================================
/**
* @internal
* Loads Value from Storage
* Loads/Saves Storage Value for the first Time
*/
initialLoading() {
const _super = Object.create(null, {
initialLoading: { get: () => super.initialLoading }
});
return __awaiter(this, void 0, void 0, function* () {
_super.initialLoading.call(this).then(() => {
this.state().isPersisted = true;
});
});
}
//=========================================================================================================
// Load Persisted Value
//=========================================================================================================
/**
* @internal
* Loads State Value from the Storage
* @return Success?
*/
loadValue() {
loadPersistedValue(key) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.ready)
return false;
const loadedValue = yield this.agileInstance().storage.get(this._key);
if (loadedValue) {
this.state().set(loadedValue, { storage: false });
return true;
}
return false;
const _key = key || this._key;
// Load Value from default Storage
const loadedValue = yield this.agileInstance().storages.get(_key, this.defaultStorageKey);
if (!loadedValue)
return false;
// Assign loaded Value to State
this.state().set(loadedValue, { storage: false });
// Persist State, so that the Storage Value updates dynamically if the State updates
yield this.persistValue(_key);
return true;
});
}
//=========================================================================================================
// Set Value
// Persist Value
//=========================================================================================================
/**
* @internal
* Saves/Updates Value in Storage
* Sets everything up so that the State gets saved in the Storage on every Value change
* @return Success?
*/
updateValue() {
persistValue(key) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.ready)
return false;
this.agileInstance().storage.set(this.key, this.state().getPersistableValue());
this.state().isPersisted = true;
const _key = key || this._key;
// Add SideEffect to State, that updates the saved State Value depending on the current State Value
this.state().addSideEffect(StatePersistent.storeValueSideEffectKey, (config) => {
this.rebuildStorageSideEffect(this.state(), _key, config);
});
// Rebuild Storage for saving State Value in the Storage
this.rebuildStorageSideEffect(this.state(), _key);
this.isPersisted = true;
return true;

@@ -109,15 +136,19 @@ });

//=========================================================================================================
// Remove Value
// Remove Persisted Value
//=========================================================================================================
/**
* @internal
* Removes Value form Storage
* Removes State Value form the Storage
* @return Success?
*/
removeValue() {
removePersistedValue(key) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.ready)
return false;
this.agileInstance().storage.remove(this.key);
this.state().isPersisted = false;
const _key = key || this._key;
// Remove SideEffect
this.state().removeSideEffect(StatePersistent.storeValueSideEffectKey);
// Remove Value from Storage
this.agileInstance().storages.remove(_key, this.storageKeys);
this.isPersisted = false;
return true;

@@ -127,23 +158,38 @@ });

//=========================================================================================================
// Validate Key
// Format Key
//=========================================================================================================
/**
* @internal
* Validates Storage Key
* @param key - Key that gets validated
* Formats Storage Key
* @param key - Key that gets formatted
*/
validateKey(key) {
formatKey(key) {
const state = this.state();
// Get key from State
if (!key && state.key)
return state.key;
// Return null if no key found
if (!key && state._key)
return state._key;
if (!key)
return null;
return;
// Set State Key to Storage Key if State has no key
if (!state.key)
state.key = key;
if (!state._key)
state._key = key;
return key;
}
//=========================================================================================================
// Rebuild Storage SideEffect
//=========================================================================================================
/**
* @internal
* Rebuilds Storage depending on the State Value (Saves current State Value into the Storage)
* @param state - State that holds the new Value
* @param key - Key/Name of Persistent
* @param config - Config
*/
rebuildStorageSideEffect(state, key, config = {}) {
if (config.storage !== undefined && !config.storage)
return;
this.agileInstance().storages.set(key, this.state().getPersistableValue(), this.storageKeys);
}
}
exports.StatePersistent = StatePersistent;
StatePersistent.storeValueSideEffectKey = "rebuildStateStorageValue";

@@ -5,6 +5,6 @@ import { Agile } from "./internal";

* Creates a fresh copy of an Array/Object
* https://www.samanthaming.com/tidbits/70-3-ways-to-clone-objects/
* @param value - Array/Object that gets copied
*/
export declare function copy<T = any>(value: T): T;
export declare function copy<T extends Array<T>>(value: T): T[];
/**

@@ -19,11 +19,21 @@ * @internal

* @internal
* Check if array1 contains all elements of array2
* @param array1 - Array 1
* @param array2 - Array 2
*/
export declare function includesArray<DataType = any>(array1: Array<DataType>, array2: Array<DataType>): boolean;
/**
* @internal
* Transforms Item/s to an Item Array
* @param items - Item/s that gets transformed to an Array
* @param config - Config
*/
export declare function normalizeArray<DataType = any>(items?: DataType | Array<DataType>): Array<DataType>;
export declare function normalizeArray<DataType = any>(items?: DataType | Array<DataType>, config?: {
createUndefinedArray?: boolean;
}): Array<DataType>;
/**
* @internal
* Tries to get an AgileInstance from provided instance
* If no agileInstance found it returns the global AgileInstance
* @param instance - Instance that might hold an AgileInstance
* Tries to get an Instance of Agile from provided Instance
* If no agileInstance found it returns the global bound Agile Instance
* @param instance - Instance that might hold an Agile Instance
*/

@@ -61,4 +71,5 @@ export declare function getAgileInstance(instance: any): Agile | undefined;

* @param defaults - Default values object that gets merged into config object
* @param overwriteUndefinedProperties - If undefined Properties in config gets overwritten by the default value
*/
export declare function defineConfig<ConfigInterface = Object>(config: ConfigInterface, defaults: Object): ConfigInterface;
export declare function defineConfig<ConfigInterface = Object>(config: ConfigInterface, defaults: Object, overwriteUndefinedProperties?: boolean): ConfigInterface;
/**

@@ -104,10 +115,12 @@ * @internal

*/
export declare function clone<T>(instance: T): T;
export declare function clone<T = any>(instance: T): T;
/**
* @internal
* Binds Instance Global
* Binds passed Instance globally at passed Key
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis
* @param key - Key of Instance
* @param instance - Instance which becomes globally accessible (globalThis.key)
* https://blog.logrocket.com/what-is-globalthis-why-use-it/
* @param key - Key/Name of Instance
* @param instance - Instance
* @param overwrite - If already existing instance at passed Key gets overwritten
*/
export declare function globalBind(key: string, instance: any): void;
export declare function globalBind(key: string, instance: any, overwrite?: boolean): boolean;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.globalBind = exports.clone = exports.generateId = exports.notEqual = exports.equal = exports.flatMerge = exports.defineConfig = exports.isJsonString = exports.isValidUrl = exports.isAsyncFunction = exports.isFunction = exports.getAgileInstance = exports.normalizeArray = exports.isValidObject = exports.copy = void 0;
exports.globalBind = exports.clone = exports.generateId = exports.notEqual = exports.equal = exports.flatMerge = exports.defineConfig = exports.isJsonString = exports.isValidUrl = exports.isAsyncFunction = exports.isFunction = exports.getAgileInstance = exports.normalizeArray = exports.includesArray = exports.isValidObject = exports.copy = void 0;
const internal_1 = require("./internal");
//=========================================================================================================
// Copy
//=========================================================================================================
/**
* @internal
* Creates a fresh copy of an Array/Object
* https://www.samanthaming.com/tidbits/70-3-ways-to-clone-objects/
* @param value - Array/Object that gets copied
*/
function copy(value) {
if (Array.isArray(value))
return [...value];
if (isValidObject(value))
return Object.assign({}, value);
return value;
// Extra checking '!value' because 'typeof null === object'
if (!value || typeof value !== "object")
return value;
let temp;
let newObject = Array.isArray(value) ? [] : {};
for (let property in value) {
temp = value[property];
newObject[property] = typeof temp === "object" ? copy(temp) : temp;
}
return newObject;
}

@@ -41,2 +55,15 @@ exports.copy = copy;

//=========================================================================================================
// Includes Array
//=========================================================================================================
/**
* @internal
* Check if array1 contains all elements of array2
* @param array1 - Array 1
* @param array2 - Array 2
*/
function includesArray(array1, array2) {
return array2.every((element) => array1.includes(element));
}
exports.includesArray = includesArray;
//=========================================================================================================
// Normalize Array

@@ -48,5 +75,9 @@ //=========================================================================================================

* @param items - Item/s that gets transformed to an Array
* @param config - Config
*/
function normalizeArray(items) {
if (!items)
function normalizeArray(items, config = {}) {
config = defineConfig(config, {
createUndefinedArray: false,
});
if (!items && !config.createUndefinedArray)
return [];

@@ -61,23 +92,21 @@ return Array.isArray(items) ? items : [items];

* @internal
* Tries to get an AgileInstance from provided instance
* If no agileInstance found it returns the global AgileInstance
* @param instance - Instance that might hold an AgileInstance
* Tries to get an Instance of Agile from provided Instance
* If no agileInstance found it returns the global bound Agile Instance
* @param instance - Instance that might hold an Agile Instance
*/
function getAgileInstance(instance) {
try {
// Try to find agileInstance in Instance
if (instance instanceof internal_1.State)
return instance.agileInstance();
if (instance instanceof internal_1.Event)
return instance.agileInstance();
if (instance instanceof internal_1.Collection)
return instance.agileInstance();
const _instance = instance["agileInstance"];
if (_instance)
return instance;
// Return global bound agileInstance (set in first instantiation of Agile)
return globalThis.__agile__;
// Try to get agileInstance from passed Instance
if (instance) {
const _agileInstance = isFunction(instance["agileInstance"])
? instance["agileInstance"]()
: instance["agileInstance"];
if (_agileInstance)
return _agileInstance;
}
// Return global bound agileInstance
return globalThis["__agile__"];
}
catch (e) {
// fail silently
internal_1.Agile.logger.error("Failed to get Agile Instance from ", instance);
}

@@ -108,3 +137,6 @@ return undefined;

function isAsyncFunction(value) {
return isFunction(value) && value.constructor.name === "AsyncFunction";
const valueString = value.toString();
return (isFunction(value) &&
(value.constructor.name === "AsyncFunction" ||
valueString.includes("__awaiter")));
}

@@ -140,2 +172,4 @@ exports.isAsyncFunction = isAsyncFunction;

function isJsonString(value) {
if (typeof value !== "string")
return false;
try {

@@ -158,4 +192,14 @@ JSON.parse(value);

* @param defaults - Default values object that gets merged into config object
* @param overwriteUndefinedProperties - If undefined Properties in config gets overwritten by the default value
*/
function defineConfig(config, defaults) {
function defineConfig(config, defaults, overwriteUndefinedProperties) {
if (overwriteUndefinedProperties === undefined)
overwriteUndefinedProperties = true;
if (overwriteUndefinedProperties) {
const finalConfig = Object.assign(Object.assign({}, defaults), config);
for (let key in finalConfig)
if (finalConfig[key] === undefined)
finalConfig[key] = defaults[key];
return finalConfig;
}
return Object.assign(Object.assign({}, defaults), config);

@@ -209,3 +253,3 @@ }

function notEqual(value1, value2) {
return value1 !== value2 && JSON.stringify(value1) !== JSON.stringify(value2);
return !equal(value1, value2);
}

@@ -242,4 +286,9 @@ exports.notEqual = notEqual;

function clone(instance) {
const copy = Object.create(Object.getPrototypeOf(instance));
return Object.assign(copy, instance);
// Clone Class
const objectCopy = Object.create(Object.getPrototypeOf(instance));
const objectClone = Object.assign(objectCopy, instance);
// Copy Properties of Class
for (let key in objectClone)
objectClone[key] = copy(objectClone[key]);
return objectClone;
}

@@ -252,16 +301,25 @@ exports.clone = clone;

* @internal
* Binds Instance Global
* Binds passed Instance globally at passed Key
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis
* @param key - Key of Instance
* @param instance - Instance which becomes globally accessible (globalThis.key)
* https://blog.logrocket.com/what-is-globalthis-why-use-it/
* @param key - Key/Name of Instance
* @param instance - Instance
* @param overwrite - If already existing instance at passed Key gets overwritten
*/
function globalBind(key, instance) {
function globalBind(key, instance, overwrite = false) {
try {
if (!globalThis[key])
if (overwrite) {
globalThis[key] = instance;
return true;
}
if (!globalThis[key]) {
globalThis[key] = instance;
return true;
}
}
catch (e) {
console.warn(`Agile: Failed to create global Instance called '${name}'`, instance);
internal_1.Agile.logger.error(`Failed to create global Instance called '${key}'`);
}
return false;
}
exports.globalBind = globalBind;
{
"name": "@agile-ts/core",
"version": "0.0.5",
"version": "0.0.6",
"author": "BennoDev",
"license": "ISC",
"homepage": "https://agile-ts.org/",
"description": "Global state and logic framework for reactive JavaScript & TypeScript applications.",

@@ -16,15 +17,2 @@ "keywords": [],

},
"devDependencies": {
"@types/chai": "^4.2.12",
"@types/mocha": "^8.0.2",
"@types/node": "^14.6.0",
"chai": "^4.2.0",
"eslint-config-prettier": "^6.11.0",
"mocha": "^8.1.1",
"prettier": "2.0.5",
"ts-node": "^8.10.2",
"tsc-watch": "^4.1.0",
"tslib": "^2.0.0",
"typescript": "^3.9.7"
},
"publishConfig": {

@@ -31,0 +19,0 @@ "access": "public"

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