@cervello/react 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Cervello
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@cervello/react?color=blue&style=flat-square)](https://www.npmjs.com/package/@cervello/react)
4
+ [![dfs](https://img.shields.io/bundlephobia/minzip/@cervello/react/latest?color=orange&style=flat-square)](https://bundlephobia.com/package/@cervello/react@latest)
4
5
 
5
6
 
6
7
  <a href="https://www.cervello.dev">
@@ -1 +1 @@
1
- {"version":3,"file":"cervello.cjs","sources":["../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/constants.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","export const INTERNAL_VALUE_PROP = '$$value$$'\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
1
+ {"version":3,"file":"cervello.cjs","sources":["../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/constants.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","export const INTERNAL_VALUE_PROP = '$$value$$'\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): T => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cervello.esm.js","sources":["../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/constants.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","export const INTERNAL_VALUE_PROP = '$$value$$'\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
1
+ {"version":3,"file":"cervello.esm.js","sources":["../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/constants.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","export const INTERNAL_VALUE_PROP = '$$value$$'\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): T => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cervello.umd.js","sources":["../src/lib/helpers/constants.ts","../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["export const INTERNAL_VALUE_PROP = '$$value$$'\n","import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["INTERNAL_VALUE_PROP","deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
1
+ {"version":3,"file":"cervello.umd.js","sources":["../src/lib/helpers/constants.ts","../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["export const INTERNAL_VALUE_PROP = '$$value$$'\n","import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): T => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["INTERNAL_VALUE_PROP","deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cervello/react",
3
3
  "type": "module",
4
- "version": "1.0.2",
4
+ "version": "1.0.4",
5
5
  "description": "🤯 Simplest and truly reactive state manager for React",
6
6
  "author": "Chempo",
7
7
  "license": "MIT",
@@ -7,4 +7,4 @@ export declare type ObjectFromAttributes<T, Attributes extends Array<keyof Witho
7
7
  [k in Attributes[number]]: T[k];
8
8
  };
9
9
  export declare type Maybe<T> = T | undefined;
10
- export declare type UseSelector<T> = <Attributes extends Array<Exclude<keyof WithoutType<T, Function>, '$value'>>>(selectors: Attributes, isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean) => ObjectFromAttributes<T, Attributes>;
10
+ export declare type UseSelector<T> = <Attributes extends Array<Exclude<keyof WithoutType<T, Function>, '$value'>>>(selectors: Attributes, isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean) => T;