@cervello/react 2.0.3 β 5.0.0-beta.2
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 +30 -29
- package/dist/cervello.cjs +1 -1
- package/dist/cervello.cjs.map +1 -1
- package/dist/cervello.esm.js +1 -1
- package/dist/cervello.esm.js.map +1 -1
- package/dist/cervello.umd.js +1 -1
- package/dist/cervello.umd.js.map +1 -1
- package/package.json +18 -16
- package/types/index.d.ts +2 -2
- package/types/lib/helpers/new-proxify-store.d.ts +7 -0
- package/types/lib/store/new-index.d.ts +20 -0
- package/types/types/shared.d.ts +12 -0
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<img src="https://github.com/chempogonzalez/cervello/blob/main/assets/emoji-logo.png" style="display:block;">
|
|
8
8
|
</a>
|
|
9
9
|
|
|
10
|
-
> π€―
|
|
10
|
+
> π€― Simple, reactive, tiny and performant state-management library for React _(just 1.5kb)_
|
|
11
11
|
|
|
12
12
|
<br>
|
|
13
13
|
<br>
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
|
|
23
23
|
## π **Features**
|
|
24
24
|
|
|
25
|
-
- βοΈ
|
|
26
|
-
- β
|
|
27
|
-
-
|
|
28
|
-
-
|
|
25
|
+
- βοΈ Reactive with store object changes **_(nested properties too π!!)_**
|
|
26
|
+
- β
Simple & minimalistic API
|
|
27
|
+
- π Batched updates and optimized re-renders
|
|
28
|
+
- π¨ Lazy listen nested properties
|
|
29
29
|
- π Immutable changes
|
|
30
30
|
- π Typescript support
|
|
31
31
|
|
|
@@ -44,45 +44,46 @@ yarn add @cervello/react
|
|
|
44
44
|
|
|
45
45
|
## π» **Quick Usage**
|
|
46
46
|
|
|
47
|
-
The `cervello` function allows you to create a new store in an easy way.
|
|
48
|
-
Just set the initial value _`(the type will be inferred based on this value)`_ and you have it!
|
|
47
|
+
<!-- The `cervello` function allows you to create a new store in an easy way. -->
|
|
48
|
+
<!-- Just set the initial value _`(the type will be inferred based on this value)`_ and you have it! -->
|
|
49
|
+
|
|
50
|
+
It's **as simple as reassign a new value** to the store properties. <br/>It will notify all the components using `useStore` hook to re-render with the new value.
|
|
49
51
|
|
|
50
52
|
```ts
|
|
51
53
|
// - store-example.ts
|
|
52
54
|
import { cervello } from '@cervello/react'
|
|
53
55
|
|
|
54
56
|
export const {
|
|
55
|
-
store, //
|
|
56
|
-
useStore, // Hook to listen for store changes
|
|
57
|
-
useSelector, // Hook to listen for changes on parts of the store
|
|
57
|
+
store, // Object with reactive changes
|
|
58
|
+
useStore, // Hook to listen for store or partial store changes
|
|
58
59
|
reset, // Function to reset the store to initial value
|
|
59
60
|
} = cervello({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
fullName: 'Cervello Store',
|
|
62
|
+
address: {
|
|
63
|
+
city: 'Huelva',
|
|
64
|
+
/* ... */
|
|
65
|
+
},
|
|
63
66
|
})
|
|
64
67
|
|
|
65
68
|
|
|
66
|
-
//
|
|
67
|
-
|
|
69
|
+
// Change value from anywhere
|
|
70
|
+
store.address.city = 'Sevilla'
|
|
68
71
|
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
{count}
|
|
75
|
-
</button>
|
|
76
|
-
)
|
|
73
|
+
// Listen for changes from components
|
|
74
|
+
function Address() {
|
|
75
|
+
const { address } = useStore()
|
|
76
|
+
return (<p>City: {address.city}</p>)
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
|
|
80
|
+
// Just listen for changes in the `city` property
|
|
81
|
+
const AddressWithSelector = () => {
|
|
82
|
+
const { address } = useStore({
|
|
83
|
+
select: ['address.city']
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return (<p>City: {address.city}</p>)
|
|
86
87
|
}
|
|
87
88
|
```
|
|
88
89
|
|
package/dist/cervello.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=require("react");function t(e){if(!e||"object"!=typeof e)return e;var n={};return Array.isArray(e)?n=e.map(function(e){return
|
|
1
|
+
var e=require("react"),n=Symbol("nonReactiveObject");function t(){return t=Object.assign?Object.assign.bind():function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])}return e},t.apply(this,arguments)}function r(e){if(!e||"object"!=typeof e)return e;var n={};return Array.isArray(e)?n=e.map(function(e){return r(e)}):e.hasOwnProperty("$$typeof")?n=e:(Object.entries(e).forEach(function(e){n[e[0]]=r(e[1])}),Object.getOwnPropertySymbols(e).forEach(function(t){n[t]=r(e[t])})),n}var u=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)};"hasOwn"in Object||(Object.hasOwn=Object.call.bind(Object.hasOwnProperty));var o=Symbol("value");function i(a,l,c){var f,s;void 0===c&&(c={});var v=null!=(f=c.nestedFieldPath)?f:"root",h=((s={})[o]=l,s),y="root"===v?Object.fromEntries(Object.entries(l).filter(function(e){return"function"==typeof e[1]})):{};return new Proxy(h,{get:function(t,l,f){if("_$fieldPath"===l)return v;var s=Object.hasOwn(t,o)?t[o]:t;if("toJSON"===l)return function(){return s};if("$value"===l)return r(s);var h,y=Reflect.get(s,l,f);if("symbol"==typeof l)return y;if("function"==typeof y)return y.bind(f);if(u(h=y)&&!e.isValidElement(h)&&!h[n]){var b,p=v+"."+l;if(y._$fieldPath===p)return y;var O=i(a,y,{nestedFieldPath:p,parentObjectToProxify:null!=(b=c.parentObjectToProxify)?b:s,afterChange:c.afterChange});return s[l]=O}return y},set:function(r,i,l,f){var s,h;if("symbol"==typeof i)return!0;var b=l,p=Object.hasOwn(r,o);if(p&&"$value"===i){var O=r[o];return b===O||JSON.stringify(b)===JSON.stringify(r[o])||("root"!==v?r[o]=b:(r[o]=t({},y,b),a.next({storeValue:r[o],change:{fieldPath:"root",newValue:b,previousValue:O}}))),!0}var g=p?r[o]:r,d=Reflect.get(g,i,f);if(d===b)return!0;u(b)&&!e.isValidElement(b)&&!b[n]&&d._$fieldPath?d.$value=b:Reflect.set(g,i,b,g);var P={storeValue:null!=(s=null==(h=c)?void 0:h.parentObjectToProxify)?s:g,change:{fieldPath:(v+"."+i).replace("root.",""),newValue:b,previousValue:d}};return a.next(P),null==c.afterChange||c.afterChange([P]),!0},has:function(e,n){return Reflect.has(e[o],n)},ownKeys:function(e){return Reflect.ownKeys(e[o])},getOwnPropertyDescriptor:function(e,n){return Reflect.getOwnPropertyDescriptor(e[o],n)}})}exports.cervello=function(n,t){var u=(null!=t?t:{}).afterChange,o=r(n),a=function(e,n){void 0===n&&(n=!1);var t=!1,r=[],u=[],o=e;return{getValue:function(){return o},next:function(e){o=e,r.push(e),t||(t=!0,Promise.resolve().then(function(){u.forEach(function(e){e.next(r)}),r=[],t=!1}))},subscribe:function(e){return n&&e.next(o),u.push(e),{unsubscribe:function(){u=u.filter(function(n){return n!==e})}}},unSubscribeAll:function(){u=[]}}}(o),l=i(a,o,{afterChange:u});return{store:l,reset:function(){l.$value=r(n)},useStore:function(n){var t,r,u=null==n||null==(t=n.initialValue)?void 0:t.apply(l,[l.$value]),o=e.useRef(!1);!o.current&&u&&u!==l&&(o.current=!0,l.$value=u);var i=e.useRef(null!=(r="function"==typeof(null==n?void 0:n.select)?null==n||null==n.select?void 0:n.select():null==n?void 0:n.select)?r:[]),c=e.useRef(i.current.filter(function(e){return e.includes(".*")}).map(function(e){return e.replace(".*","")}));return e.useLayoutEffect(function(){null!=n&&n.setValueOnMount&&n.setValueOnMount(l.$value).then(function(e){l.$value=e}).catch(function(e){console.error("Error setting initial value on mount",e)})},[]),e.useSyncExternalStore(function(e){var t=a.subscribe({next:function(t){var r=Array.isArray(t)?t:[t];if(null==n||!n.select)return e(),void(null==n||null==n.onChange||n.onChange(r));r.some(function(e){return"root"===e.change.fieldPath||i.current.includes(e.change.fieldPath)||c.current.find(function(n){return e.change.fieldPath.startsWith(n)})})&&(e(),null==n||null==n.onChange||n.onChange(r))}});return function(){t.unsubscribe()}},function(){return a.getValue()},function(){return a.getValue()}),l}}};
|
|
2
2
|
//# sourceMappingURL=cervello.cjs.map
|
package/dist/cervello.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cervello.cjs","sources":["../src/lib/utils/object.ts","../src/lib/utils/string.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","\nexport function capitalize (str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport function isCamelCase (str: string): boolean {\n const regex = /^[a-z]+([A-Z][a-z]*)*$/\n\n return regex.test(str)\n}\n","\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { deepClone, isObject, okTarget } from '../utils'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol' && !Object.hasOwn(propertyValue, '$$typeof')) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol' && !Object.hasOwn(newValue, '$$typeof')) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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, useSyncExternalStore } from 'react'\n\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { contentComparer, deepClone, getPartialObjectFromProperties } from '../utils'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol.for('_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 >(\n type === 'full'\n ? null\n // To avoid the first render to be always different even\n // if store changed other than selected attributes\n : getPartialObjectFromProperties(selectors, (store$$.getValue() as any)?.[INTERNAL_VALUE_PROP]),\n )\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') {\n onStoreChange()\n\n return\n }\n\n // Partial store section ------------------------------------------------------------------\n const currentSlice = getPartialObjectFromProperties(selectors, (v as any)?.[INTERNAL_VALUE_PROP])\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n\n if (!isEquals) {\n /**\n * Update previous slice with deepClone to avoid storing direct store$$ value reference.\n * This solve reference/value problems when changing the store object\n * (proxy.set is changing the target object which is 'v' here)\n */\n prevSlice.current = deepClone(currentSlice)\n onStoreChange()\n }\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","\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 capitalize,\n isCamelCase,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ntype 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\ndeclare type Prettify<T> = {} & {\n [K in keyof T]: T[K];\n}\n\n\n\n\ntype CervelloStore<StoreType, StoreName extends string | undefined = undefined> =\n StoreName extends string\n ? Prettify<{\n // /** Reactive store */\n [K in `${StoreName}Store`]: StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Store`]: () => StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Selector`]: UseSelector<StoreType>\n }\n & {\n /** Resets the value to the initial value passed in */\n [K in `reset${Capitalize<StoreName>}Store`]: () => void\n }\n & {\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType, StoreName>\n }>\n :\n {\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, StoreName>\n }\n\n\nexport type CervelloOptions<StoreName extends string | undefined = undefined> = {\n name?: StoreName\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 - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT,\nStoreName extends string | undefined = undefined,\n> (initialValue: () => T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\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 \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT extends Record<string, unknown>,\nStoreName extends string | undefined = undefined,\n> (initialValue: T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\n\n\n\n/** @internal */\nexport function cervello <T, StoreName extends string | undefined = undefined> (\n initialValue: T | (() => T),\n options: CervelloOptions<StoreName> = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }, StoreName> {\n const { name: optionsName, reactiveNestedObjects = true } = options\n\n if (optionsName && !isCamelCase(optionsName))\n throw new Error(`[cervello]: options.name must be in camelCase and \"${optionsName}\" doesn't respect this rule.`)\n\n\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, reactiveNestedObjects)\n\n const cervelloStore = {\n [optionsName\n ? `${optionsName}Store`\n : 'store'\n ]: proxiedStore,\n\n [optionsName\n ? `reset${capitalize(optionsName)}Store`\n : 'reset'\n ] () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n [optionsName\n ? `use${capitalize(optionsName)}Store`\n : 'useStore'\n ]: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n\n [optionsName\n ? `use${capitalize(optionsName)}Selector`\n : 'useSelector'\n ]: 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\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\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n\n return this\n },\n } as any\n\n\n\n return cervelloStore\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\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","capitalize","str","charAt","toUpperCase","slice","hasOwn","call","bind","hasOwnProperty","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","INTERNAL_VALUE_PROP","_newClonedValue","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","_store$$$getValue","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","initialValue","options","reactiveNestedObjects","optionsName","name","_options$reactiveNest","test","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","value","o","observer","push","filter","unSubscribeAll","cervelloStore","$value","_cervelloStore","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cervello.cjs","sources":["../src/types/shared.ts","../src/lib/utils/object.ts","../src/lib/helpers/new-proxify-store.ts","../src/lib/store/new-index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-types */\nexport type WithoutType<T, V, WithNever = {\n [K in keyof T]: Exclude<T[K], undefined> extends V\n ? never\n : (T[K] extends Record<string, unknown>\n ? WithoutType<T[K], V>\n : T[K])\n}> = Pick<WithNever, {\n [K in keyof WithNever]: WithNever[K] extends never ? never : K\n}[keyof WithNever]>\n\n\n\nexport type ObjectFromAttributes<T, Attributes extends Array< keyof WithoutType<T, Function> > > = {\n [k in Attributes[number]]: T[k]\n}\n\nexport type Maybe<T> = T | undefined\n\n\n\nexport type UseSelector<T> = <Attributes extends Array< Exclude<keyof WithoutType<T, Function>, '$value'> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n) => T\n\nexport type FieldPath<T extends Record<string, any>> = {\n [K in keyof Required<T>]: T[K] extends Record<string, any>\n ? K extends string\n\n ? T[K] extends Function\n ? never\n : T[K] extends Array<any>\n ? K\n : `${K}.*` | `${K}.${FieldPath<T[K]>}`\n : never\n : K extends string\n ? K\n : never\n}[keyof T]\n\nexport const nonReactiveObjectSymbol = Symbol('nonReactiveObject')\nexport type StoreChange<T extends Record<string, any>> = {\n change: {\n fieldPath: FieldPath<T>\n newValue: any\n previousValue: any\n }\n storeValue: T\n}\n","\nimport { 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\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n // eslint-disable-next-line no-prototype-builtins\n } else if (!obj.hasOwnProperty('$$typeof')) {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n Object.getOwnPropertySymbols(obj).forEach((symbol) => {\n newObj[symbol] = deepClone((obj as any)[symbol])\n })\n } else {\n newObj = obj\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\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n\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 { isValidElement } from 'react'\n\nimport { nonReactiveObjectSymbol } from '../../types/shared'\nimport { deepClone, isObject } from '../utils/object'\n\nimport type { StoreChange } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst ROOT_VALUE = Symbol('value')\n\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<StoreChange<T>>,\n objectToProxify: T,\n opts: {\n nestedFieldPath?: string\n parentObjectToProxify?: any\n // beforeChange?: (storeChange: StoreChange<T>) => any\n afterChange?: (storeChange: Array<StoreChange<T>>) => void\n } = {},\n): T {\n const fieldPath = opts.nestedFieldPath ?? 'root'\n\n const objectWithRootValue = {\n [ROOT_VALUE]: objectToProxify,\n } as unknown as T\n\n const rootFunctions = fieldPath === 'root'\n ? Object.fromEntries(Object.entries(objectToProxify).filter(([,v]) => typeof v === 'function'))\n : {}\n\n return new Proxy(objectWithRootValue, {\n get (targetObject, propName, receiver) {\n if (propName === '_$fieldPath') return fieldPath\n\n const isRootTarget = Object.hasOwn(targetObject, ROOT_VALUE)\n const target = isRootTarget ? targetObject[ROOT_VALUE] : targetObject\n\n if (propName === 'toJSON') return () => target\n\n if (propName === '$value') return deepClone(target)\n\n const propertyValue = Reflect.get(target, propName, receiver)\n\n if (typeof propName === 'symbol') return propertyValue\n\n\n if (typeof propertyValue === 'function')\n return (propertyValue as () => any).bind(receiver)\n\n\n if (isValidReactiveObject(propertyValue)) {\n const newNestedFieldPath = `${fieldPath}.${propName}`\n\n\n if (propertyValue._$fieldPath === newNestedFieldPath) return propertyValue\n\n const proxiedNestedObject = proxifyStore(\n store$$ as any,\n propertyValue,\n {\n nestedFieldPath: newNestedFieldPath,\n parentObjectToProxify: opts.parentObjectToProxify ?? target,\n // beforeChange: opts.beforeChange,\n afterChange: opts.afterChange,\n },\n )\n\n return target[propName] = proxiedNestedObject\n }\n\n return propertyValue\n },\n\n\n set (parentObject, key, newValue, receiver) {\n if (typeof key === 'symbol') return true\n\n const value = newValue\n const isRootTarget = Object.hasOwn(parentObject, ROOT_VALUE)\n\n if (isRootTarget && key === '$value') {\n const previousValue = parentObject[ROOT_VALUE]\n\n if (value === previousValue) return true\n if (JSON.stringify(value) === JSON.stringify(parentObject[ROOT_VALUE])) return true\n\n if (fieldPath !== 'root') {\n (parentObject as any)[ROOT_VALUE] = value\n } else {\n (parentObject as any)[ROOT_VALUE] = {\n ...rootFunctions,\n ...value,\n }\n store$$.next({\n // To be disabled for performance and send same store reference\n // storeValue: JSON.parse(JSON.stringify(targetObject[ROOT_VALUE])),\n storeValue: parentObject[ROOT_VALUE],\n change: {\n fieldPath: 'root' as any,\n newValue: value,\n previousValue,\n },\n })\n }\n\n return true\n }\n\n const realInnerObject = isRootTarget ? parentObject[ROOT_VALUE] : parentObject\n const previousValue = Reflect.get(realInnerObject, key, receiver)\n\n\n if (previousValue === value)\n return true\n\n\n // New object values, check if the field has already a proxy created to use it instead of reacreating a new instance\n if (isObject(value) && !isValidElement(value) && !value[nonReactiveObjectSymbol] && previousValue._$fieldPath)\n previousValue.$value = value\n else\n Reflect.set(realInnerObject, key, value, realInnerObject)\n\n\n const nextStoreChange = {\n // To be disabled for performance and send same store reference\n // storeValue: JSON.parse(JSON.stringify(opts?.parentObjectToProxify ?? target)),\n storeValue: opts?.parentObjectToProxify ?? realInnerObject,\n change: {\n fieldPath: `${fieldPath}.${key}`.replace('root.', '') as any,\n newValue: value,\n previousValue,\n },\n }\n\n store$$.next(nextStoreChange)\n opts.afterChange?.([nextStoreChange])\n\n return true\n },\n\n has (t, p) {\n return Reflect.has(t[ROOT_VALUE], p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(t[ROOT_VALUE])\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(t[ROOT_VALUE], p)\n },\n\n })\n}\n\n\nfunction isValidReactiveObject <T extends Record<string, any>> (value: T): boolean {\n return isObject(value) && !isValidElement(value) && !(value as any)[nonReactiveObjectSymbol]\n}\n","\nimport { useLayoutEffect, useRef, useSyncExternalStore } from 'react'\n\nimport { nonReactiveObjectSymbol } from '../../types/shared'\nimport { proxifyStore } from '../helpers/new-proxify-store'\nimport { deepClone } from '../utils/object'\nimport { createCacheableSubject } from '../utils/subject'\n\nimport type { FieldPath, StoreChange } from '../../types/shared'\n\n\n\n\n// export type CervelloOptions<StoreValue extends Record<string, any>> = {\n// beforeChange?: (storeChange: StoreChange<StoreValue>) => unknown | undefined\n// afterChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n// }\n\nexport type CervelloOptions<StoreValue extends Record<string, any>> = {\n afterChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n}\n\nexport type CervelloUseStoreOptions<StoreValue extends Record<string, any>> = {\n initialValue?: (currentStore: StoreValue) => StoreValue,\n setValueOnMount?: (currentStore: StoreValue) => Promise<StoreValue>,\n select?:\n | Array<FieldPath<StoreValue>>\n | (() => Array<FieldPath<StoreValue>>)\n onChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n}\n\ntype MutableStoreValue<T extends Record<string, any>> = {\n $value: T\n} & T\n\n\n\n\n\n\n\n\nexport function nonReactive <T extends Record<string, any>> (initialValue: T): T {\n Object.defineProperty(initialValue, nonReactiveObjectSymbol, {\n value: true,\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n return initialValue\n}\n\n\nexport function cervello <StoreValue extends Record<PropertyKey, any>> (\n initialValue: StoreValue,\n options?: CervelloOptions<StoreValue>,\n): {\n store: MutableStoreValue<StoreValue>,\n reset: () => void,\n useStore: (options?: CervelloUseStoreOptions<StoreValue>) => MutableStoreValue<StoreValue>\n } {\n const {\n // beforeChange,\n afterChange,\n } = options ?? {}\n\n const clonedInitialValue = deepClone(initialValue)\n const store$$ = createCacheableSubject<StoreChange<StoreValue>>(clonedInitialValue as any)\n\n const proxiedStore = proxifyStore(\n store$$ as any,\n clonedInitialValue,\n // { beforeChange, afterChange },\n { afterChange },\n ) as MutableStoreValue<StoreValue>\n\n\n return {\n store: proxiedStore,\n reset: () => {\n proxiedStore.$value = deepClone(initialValue)\n },\n useStore: (options) => {\n const initialValue = options?.initialValue?.apply(proxiedStore, [proxiedStore.$value])\n const isInitialValueSet = useRef(false)\n\n if (!isInitialValueSet.current && initialValue && initialValue !== proxiedStore) {\n isInitialValueSet.current = true\n proxiedStore.$value = initialValue\n }\n\n const selectFieldPaths = useRef(\n (typeof options?.select === 'function'\n ? options?.select?.()\n : options?.select)\n ?? [],\n )\n\n const selectedFieldPathsForNestedObjects = useRef(\n selectFieldPaths.current\n .filter(fp => fp.includes('.*'))\n .map(fp => fp.replace('.*', '')),\n )\n\n\n useLayoutEffect(() => {\n if (options?.setValueOnMount) {\n void options.setValueOnMount(proxiedStore.$value).then((value) => {\n proxiedStore.$value = value\n }).catch((err) => {\n console.error('Error setting initial value on mount', err)\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n\n useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (sc) => {\n const storeChanges = Array.isArray(sc)\n ? sc as Array<StoreChange<StoreValue>>\n : [sc]\n\n if (!options?.select) {\n onStoreChange()\n options?.onChange?.(storeChanges)\n\n return\n }\n\n if (storeChanges.some(nextChange => (\n nextChange.change.fieldPath === 'root'\n || selectFieldPaths.current.includes(nextChange.change.fieldPath))\n || selectedFieldPathsForNestedObjects.current.find(fp => nextChange.change.fieldPath.startsWith(fp)),\n )) {\n onStoreChange()\n options?.onChange?.(storeChanges)\n }\n },\n })\n\n return () => {\n subscription.unsubscribe()\n }\n },\n () => store$$.getValue(),\n () => store$$.getValue(),\n )\n\n return proxiedStore\n },\n }\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\nconst WITH_FLUSHING = true\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = false): CacheableSubject<T> {\n let isFlushing = false\n let itemsToFlush: Array<T> = []\n\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\n if (!WITH_FLUSHING) {\n observerList.forEach((o) => { o.next(newValue) })\n\n return\n }\n\n itemsToFlush.push(newValue)\n // observerList.forEach((o) => { o.next(newValue) })\n\n if (!isFlushing) {\n isFlushing = true\n void Promise.resolve().then(() => {\n observerList.forEach((o) => { o.next(itemsToFlush as T) })\n itemsToFlush = []\n isFlushing = false\n })\n }\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\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\n"],"names":["nonReactiveObjectSymbol","Symbol","deepClone","obj","newObj","Array","isArray","map","item","hasOwnProperty","Object","entries","forEach","_ref","value","getOwnPropertySymbols","symbol","isObject","hasOwn","call","bind","ROOT_VALUE","proxifyStore","store$$","objectToProxify","opts","_opts$nestedFieldPath","_objectWithRootValue","fieldPath","nestedFieldPath","objectWithRootValue","rootFunctions","fromEntries","filter","v","Proxy","get","targetObject","propName","receiver","target","propertyValue","Reflect","isValidElement","_opts$parentObjectToP","newNestedFieldPath","_$fieldPath","proxiedNestedObject","parentObjectToProxify","afterChange","set","parentObject","key","newValue","_opts$parentObjectToP2","_opts","isRootTarget","previousValue","JSON","stringify","_extends","next","storeValue","change","realInnerObject","$value","nextStoreChange","replace","has","t","p","ownKeys","getOwnPropertyDescriptor","cervello","initialValue","options","clonedInitialValue","createCacheableSubject","defaultValue","getValueOnSubscribe","isFlushing","observerList","getValue","itemsToFlush","push","resolve","then","o","subscribe","observer","unsubscribe","unSubscribeAll","proxiedStore","store","reset","useStore","_options$initialValue","_ref2","apply","isInitialValueSet","useRef","current","selectFieldPaths","select","selectedFieldPathsForNestedObjects","fp","includes","useLayoutEffect","setValueOnMount","err","console","error","useSyncExternalStore","onStoreChange","subscription","sc","storeChanges","onChange","some","nextChange","find","startsWith"],"mappings":"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"}
|
package/dist/cervello.esm.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{isValidElement as e,useRef as n,useLayoutEffect as t,useSyncExternalStore as r}from"react";var u=Symbol("nonReactiveObject");function o(){return o=Object.assign?Object.assign.bind():function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])}return e},o.apply(this,arguments)}function i(e){if(!e||"object"!=typeof e)return e;var n={};return Array.isArray(e)?n=e.map(function(e){return i(e)}):e.hasOwnProperty("$$typeof")?n=e:(Object.entries(e).forEach(function(e){n[e[0]]=i(e[1])}),Object.getOwnPropertySymbols(e).forEach(function(t){n[t]=i(e[t])})),n}var a=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)};"hasOwn"in Object||(Object.hasOwn=Object.call.bind(Object.hasOwnProperty));var l=Symbol("value");function c(n,t,r){var f,s;void 0===r&&(r={});var v=null!=(f=r.nestedFieldPath)?f:"root",h=((s={})[l]=t,s),b="root"===v?Object.fromEntries(Object.entries(t).filter(function(e){return"function"==typeof e[1]})):{};return new Proxy(h,{get:function(t,o,f){if("_$fieldPath"===o)return v;var s=Object.hasOwn(t,l)?t[l]:t;if("toJSON"===o)return function(){return s};if("$value"===o)return i(s);var h,b=Reflect.get(s,o,f);if("symbol"==typeof o)return b;if("function"==typeof b)return b.bind(f);if(a(h=b)&&!e(h)&&!h[u]){var y,p=v+"."+o;if(b._$fieldPath===p)return b;var O=c(n,b,{nestedFieldPath:p,parentObjectToProxify:null!=(y=r.parentObjectToProxify)?y:s,afterChange:r.afterChange});return s[o]=O}return b},set:function(t,i,c,f){var s,h;if("symbol"==typeof i)return!0;var y=c,p=Object.hasOwn(t,l);if(p&&"$value"===i){var O=t[l];return y===O||JSON.stringify(y)===JSON.stringify(t[l])||("root"!==v?t[l]=y:(t[l]=o({},b,y),n.next({storeValue:t[l],change:{fieldPath:"root",newValue:y,previousValue:O}}))),!0}var g=p?t[l]:t,d=Reflect.get(g,i,f);if(d===y)return!0;a(y)&&!e(y)&&!y[u]&&d._$fieldPath?d.$value=y:Reflect.set(g,i,y,g);var P={storeValue:null!=(s=null==(h=r)?void 0:h.parentObjectToProxify)?s:g,change:{fieldPath:(v+"."+i).replace("root.",""),newValue:y,previousValue:d}};return n.next(P),null==r.afterChange||r.afterChange([P]),!0},has:function(e,n){return Reflect.has(e[l],n)},ownKeys:function(e){return Reflect.ownKeys(e[l])},getOwnPropertyDescriptor:function(e,n){return Reflect.getOwnPropertyDescriptor(e[l],n)}})}function f(e,u){var o=(null!=u?u:{}).afterChange,a=i(e),l=function(e,n){void 0===n&&(n=!1);var t=!1,r=[],u=[],o=e;return{getValue:function(){return o},next:function(e){o=e,r.push(e),t||(t=!0,Promise.resolve().then(function(){u.forEach(function(e){e.next(r)}),r=[],t=!1}))},subscribe:function(e){return n&&e.next(o),u.push(e),{unsubscribe:function(){u=u.filter(function(n){return n!==e})}}},unSubscribeAll:function(){u=[]}}}(a),f=c(l,a,{afterChange:o});return{store:f,reset:function(){f.$value=i(e)},useStore:function(e){var u,o,i=null==e||null==(u=e.initialValue)?void 0:u.apply(f,[f.$value]),a=n(!1);!a.current&&i&&i!==f&&(a.current=!0,f.$value=i);var c=n(null!=(o="function"==typeof(null==e?void 0:e.select)?null==e||null==e.select?void 0:e.select():null==e?void 0:e.select)?o:[]),s=n(c.current.filter(function(e){return e.includes(".*")}).map(function(e){return e.replace(".*","")}));return t(function(){null!=e&&e.setValueOnMount&&e.setValueOnMount(f.$value).then(function(e){f.$value=e}).catch(function(e){console.error("Error setting initial value on mount",e)})},[]),r(function(n){var t=l.subscribe({next:function(t){var r=Array.isArray(t)?t:[t];if(null==e||!e.select)return n(),void(null==e||null==e.onChange||e.onChange(r));r.some(function(e){return"root"===e.change.fieldPath||c.current.includes(e.change.fieldPath)||s.current.find(function(n){return e.change.fieldPath.startsWith(n)})})&&(n(),null==e||null==e.onChange||e.onChange(r))}});return function(){t.unsubscribe()}},function(){return l.getValue()},function(){return l.getValue()}),f}}}export{f as cervello};
|
|
2
2
|
//# sourceMappingURL=cervello.esm.js.map
|
package/dist/cervello.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cervello.esm.js","sources":["../src/lib/utils/object.ts","../src/lib/utils/string.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","\nexport function capitalize (str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport function isCamelCase (str: string): boolean {\n const regex = /^[a-z]+([A-Z][a-z]*)*$/\n\n return regex.test(str)\n}\n","\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { deepClone, isObject, okTarget } from '../utils'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol' && !Object.hasOwn(propertyValue, '$$typeof')) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol' && !Object.hasOwn(newValue, '$$typeof')) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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, useSyncExternalStore } from 'react'\n\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { contentComparer, deepClone, getPartialObjectFromProperties } from '../utils'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol.for('_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 >(\n type === 'full'\n ? null\n // To avoid the first render to be always different even\n // if store changed other than selected attributes\n : getPartialObjectFromProperties(selectors, (store$$.getValue() as any)?.[INTERNAL_VALUE_PROP]),\n )\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') {\n onStoreChange()\n\n return\n }\n\n // Partial store section ------------------------------------------------------------------\n const currentSlice = getPartialObjectFromProperties(selectors, (v as any)?.[INTERNAL_VALUE_PROP])\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n\n if (!isEquals) {\n /**\n * Update previous slice with deepClone to avoid storing direct store$$ value reference.\n * This solve reference/value problems when changing the store object\n * (proxy.set is changing the target object which is 'v' here)\n */\n prevSlice.current = deepClone(currentSlice)\n onStoreChange()\n }\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","\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 capitalize,\n isCamelCase,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ntype 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\ndeclare type Prettify<T> = {} & {\n [K in keyof T]: T[K];\n}\n\n\n\n\ntype CervelloStore<StoreType, StoreName extends string | undefined = undefined> =\n StoreName extends string\n ? Prettify<{\n // /** Reactive store */\n [K in `${StoreName}Store`]: StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Store`]: () => StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Selector`]: UseSelector<StoreType>\n }\n & {\n /** Resets the value to the initial value passed in */\n [K in `reset${Capitalize<StoreName>}Store`]: () => void\n }\n & {\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType, StoreName>\n }>\n :\n {\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, StoreName>\n }\n\n\nexport type CervelloOptions<StoreName extends string | undefined = undefined> = {\n name?: StoreName\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 - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT,\nStoreName extends string | undefined = undefined,\n> (initialValue: () => T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\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 \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT extends Record<string, unknown>,\nStoreName extends string | undefined = undefined,\n> (initialValue: T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\n\n\n\n/** @internal */\nexport function cervello <T, StoreName extends string | undefined = undefined> (\n initialValue: T | (() => T),\n options: CervelloOptions<StoreName> = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }, StoreName> {\n const { name: optionsName, reactiveNestedObjects = true } = options\n\n if (optionsName && !isCamelCase(optionsName))\n throw new Error(`[cervello]: options.name must be in camelCase and \"${optionsName}\" doesn't respect this rule.`)\n\n\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, reactiveNestedObjects)\n\n const cervelloStore = {\n [optionsName\n ? `${optionsName}Store`\n : 'store'\n ]: proxiedStore,\n\n [optionsName\n ? `reset${capitalize(optionsName)}Store`\n : 'reset'\n ] () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n [optionsName\n ? `use${capitalize(optionsName)}Store`\n : 'useStore'\n ]: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n\n [optionsName\n ? `use${capitalize(optionsName)}Selector`\n : 'useSelector'\n ]: 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\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\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n\n return this\n },\n } as any\n\n\n\n return cervelloStore\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\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","capitalize","str","charAt","toUpperCase","slice","hasOwn","call","bind","hasOwnProperty","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","INTERNAL_VALUE_PROP","_newClonedValue","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","_store$$$getValue","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","initialValue","options","reactiveNestedObjects","optionsName","name","_options$reactiveNest","test","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","value","o","observer","push","filter","unSubscribeAll","cervelloStore","$value","_cervelloStore","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cervello.esm.js","sources":["../src/types/shared.ts","../src/lib/utils/object.ts","../src/lib/helpers/new-proxify-store.ts","../src/lib/store/new-index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-types */\nexport type WithoutType<T, V, WithNever = {\n [K in keyof T]: Exclude<T[K], undefined> extends V\n ? never\n : (T[K] extends Record<string, unknown>\n ? WithoutType<T[K], V>\n : T[K])\n}> = Pick<WithNever, {\n [K in keyof WithNever]: WithNever[K] extends never ? never : K\n}[keyof WithNever]>\n\n\n\nexport type ObjectFromAttributes<T, Attributes extends Array< keyof WithoutType<T, Function> > > = {\n [k in Attributes[number]]: T[k]\n}\n\nexport type Maybe<T> = T | undefined\n\n\n\nexport type UseSelector<T> = <Attributes extends Array< Exclude<keyof WithoutType<T, Function>, '$value'> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n) => T\n\nexport type FieldPath<T extends Record<string, any>> = {\n [K in keyof Required<T>]: T[K] extends Record<string, any>\n ? K extends string\n\n ? T[K] extends Function\n ? never\n : T[K] extends Array<any>\n ? K\n : `${K}.*` | `${K}.${FieldPath<T[K]>}`\n : never\n : K extends string\n ? K\n : never\n}[keyof T]\n\nexport const nonReactiveObjectSymbol = Symbol('nonReactiveObject')\nexport type StoreChange<T extends Record<string, any>> = {\n change: {\n fieldPath: FieldPath<T>\n newValue: any\n previousValue: any\n }\n storeValue: T\n}\n","\nimport { 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\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n // eslint-disable-next-line no-prototype-builtins\n } else if (!obj.hasOwnProperty('$$typeof')) {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n Object.getOwnPropertySymbols(obj).forEach((symbol) => {\n newObj[symbol] = deepClone((obj as any)[symbol])\n })\n } else {\n newObj = obj\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\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n\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 { isValidElement } from 'react'\n\nimport { nonReactiveObjectSymbol } from '../../types/shared'\nimport { deepClone, isObject } from '../utils/object'\n\nimport type { StoreChange } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst ROOT_VALUE = Symbol('value')\n\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<StoreChange<T>>,\n objectToProxify: T,\n opts: {\n nestedFieldPath?: string\n parentObjectToProxify?: any\n // beforeChange?: (storeChange: StoreChange<T>) => any\n afterChange?: (storeChange: Array<StoreChange<T>>) => void\n } = {},\n): T {\n const fieldPath = opts.nestedFieldPath ?? 'root'\n\n const objectWithRootValue = {\n [ROOT_VALUE]: objectToProxify,\n } as unknown as T\n\n const rootFunctions = fieldPath === 'root'\n ? Object.fromEntries(Object.entries(objectToProxify).filter(([,v]) => typeof v === 'function'))\n : {}\n\n return new Proxy(objectWithRootValue, {\n get (targetObject, propName, receiver) {\n if (propName === '_$fieldPath') return fieldPath\n\n const isRootTarget = Object.hasOwn(targetObject, ROOT_VALUE)\n const target = isRootTarget ? targetObject[ROOT_VALUE] : targetObject\n\n if (propName === 'toJSON') return () => target\n\n if (propName === '$value') return deepClone(target)\n\n const propertyValue = Reflect.get(target, propName, receiver)\n\n if (typeof propName === 'symbol') return propertyValue\n\n\n if (typeof propertyValue === 'function')\n return (propertyValue as () => any).bind(receiver)\n\n\n if (isValidReactiveObject(propertyValue)) {\n const newNestedFieldPath = `${fieldPath}.${propName}`\n\n\n if (propertyValue._$fieldPath === newNestedFieldPath) return propertyValue\n\n const proxiedNestedObject = proxifyStore(\n store$$ as any,\n propertyValue,\n {\n nestedFieldPath: newNestedFieldPath,\n parentObjectToProxify: opts.parentObjectToProxify ?? target,\n // beforeChange: opts.beforeChange,\n afterChange: opts.afterChange,\n },\n )\n\n return target[propName] = proxiedNestedObject\n }\n\n return propertyValue\n },\n\n\n set (parentObject, key, newValue, receiver) {\n if (typeof key === 'symbol') return true\n\n const value = newValue\n const isRootTarget = Object.hasOwn(parentObject, ROOT_VALUE)\n\n if (isRootTarget && key === '$value') {\n const previousValue = parentObject[ROOT_VALUE]\n\n if (value === previousValue) return true\n if (JSON.stringify(value) === JSON.stringify(parentObject[ROOT_VALUE])) return true\n\n if (fieldPath !== 'root') {\n (parentObject as any)[ROOT_VALUE] = value\n } else {\n (parentObject as any)[ROOT_VALUE] = {\n ...rootFunctions,\n ...value,\n }\n store$$.next({\n // To be disabled for performance and send same store reference\n // storeValue: JSON.parse(JSON.stringify(targetObject[ROOT_VALUE])),\n storeValue: parentObject[ROOT_VALUE],\n change: {\n fieldPath: 'root' as any,\n newValue: value,\n previousValue,\n },\n })\n }\n\n return true\n }\n\n const realInnerObject = isRootTarget ? parentObject[ROOT_VALUE] : parentObject\n const previousValue = Reflect.get(realInnerObject, key, receiver)\n\n\n if (previousValue === value)\n return true\n\n\n // New object values, check if the field has already a proxy created to use it instead of reacreating a new instance\n if (isObject(value) && !isValidElement(value) && !value[nonReactiveObjectSymbol] && previousValue._$fieldPath)\n previousValue.$value = value\n else\n Reflect.set(realInnerObject, key, value, realInnerObject)\n\n\n const nextStoreChange = {\n // To be disabled for performance and send same store reference\n // storeValue: JSON.parse(JSON.stringify(opts?.parentObjectToProxify ?? target)),\n storeValue: opts?.parentObjectToProxify ?? realInnerObject,\n change: {\n fieldPath: `${fieldPath}.${key}`.replace('root.', '') as any,\n newValue: value,\n previousValue,\n },\n }\n\n store$$.next(nextStoreChange)\n opts.afterChange?.([nextStoreChange])\n\n return true\n },\n\n has (t, p) {\n return Reflect.has(t[ROOT_VALUE], p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(t[ROOT_VALUE])\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(t[ROOT_VALUE], p)\n },\n\n })\n}\n\n\nfunction isValidReactiveObject <T extends Record<string, any>> (value: T): boolean {\n return isObject(value) && !isValidElement(value) && !(value as any)[nonReactiveObjectSymbol]\n}\n","\nimport { useLayoutEffect, useRef, useSyncExternalStore } from 'react'\n\nimport { nonReactiveObjectSymbol } from '../../types/shared'\nimport { proxifyStore } from '../helpers/new-proxify-store'\nimport { deepClone } from '../utils/object'\nimport { createCacheableSubject } from '../utils/subject'\n\nimport type { FieldPath, StoreChange } from '../../types/shared'\n\n\n\n\n// export type CervelloOptions<StoreValue extends Record<string, any>> = {\n// beforeChange?: (storeChange: StoreChange<StoreValue>) => unknown | undefined\n// afterChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n// }\n\nexport type CervelloOptions<StoreValue extends Record<string, any>> = {\n afterChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n}\n\nexport type CervelloUseStoreOptions<StoreValue extends Record<string, any>> = {\n initialValue?: (currentStore: StoreValue) => StoreValue,\n setValueOnMount?: (currentStore: StoreValue) => Promise<StoreValue>,\n select?:\n | Array<FieldPath<StoreValue>>\n | (() => Array<FieldPath<StoreValue>>)\n onChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n}\n\ntype MutableStoreValue<T extends Record<string, any>> = {\n $value: T\n} & T\n\n\n\n\n\n\n\n\nexport function nonReactive <T extends Record<string, any>> (initialValue: T): T {\n Object.defineProperty(initialValue, nonReactiveObjectSymbol, {\n value: true,\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n return initialValue\n}\n\n\nexport function cervello <StoreValue extends Record<PropertyKey, any>> (\n initialValue: StoreValue,\n options?: CervelloOptions<StoreValue>,\n): {\n store: MutableStoreValue<StoreValue>,\n reset: () => void,\n useStore: (options?: CervelloUseStoreOptions<StoreValue>) => MutableStoreValue<StoreValue>\n } {\n const {\n // beforeChange,\n afterChange,\n } = options ?? {}\n\n const clonedInitialValue = deepClone(initialValue)\n const store$$ = createCacheableSubject<StoreChange<StoreValue>>(clonedInitialValue as any)\n\n const proxiedStore = proxifyStore(\n store$$ as any,\n clonedInitialValue,\n // { beforeChange, afterChange },\n { afterChange },\n ) as MutableStoreValue<StoreValue>\n\n\n return {\n store: proxiedStore,\n reset: () => {\n proxiedStore.$value = deepClone(initialValue)\n },\n useStore: (options) => {\n const initialValue = options?.initialValue?.apply(proxiedStore, [proxiedStore.$value])\n const isInitialValueSet = useRef(false)\n\n if (!isInitialValueSet.current && initialValue && initialValue !== proxiedStore) {\n isInitialValueSet.current = true\n proxiedStore.$value = initialValue\n }\n\n const selectFieldPaths = useRef(\n (typeof options?.select === 'function'\n ? options?.select?.()\n : options?.select)\n ?? [],\n )\n\n const selectedFieldPathsForNestedObjects = useRef(\n selectFieldPaths.current\n .filter(fp => fp.includes('.*'))\n .map(fp => fp.replace('.*', '')),\n )\n\n\n useLayoutEffect(() => {\n if (options?.setValueOnMount) {\n void options.setValueOnMount(proxiedStore.$value).then((value) => {\n proxiedStore.$value = value\n }).catch((err) => {\n console.error('Error setting initial value on mount', err)\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n\n useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (sc) => {\n const storeChanges = Array.isArray(sc)\n ? sc as Array<StoreChange<StoreValue>>\n : [sc]\n\n if (!options?.select) {\n onStoreChange()\n options?.onChange?.(storeChanges)\n\n return\n }\n\n if (storeChanges.some(nextChange => (\n nextChange.change.fieldPath === 'root'\n || selectFieldPaths.current.includes(nextChange.change.fieldPath))\n || selectedFieldPathsForNestedObjects.current.find(fp => nextChange.change.fieldPath.startsWith(fp)),\n )) {\n onStoreChange()\n options?.onChange?.(storeChanges)\n }\n },\n })\n\n return () => {\n subscription.unsubscribe()\n }\n },\n () => store$$.getValue(),\n () => store$$.getValue(),\n )\n\n return proxiedStore\n },\n }\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\nconst WITH_FLUSHING = true\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = false): CacheableSubject<T> {\n let isFlushing = false\n let itemsToFlush: Array<T> = []\n\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\n if (!WITH_FLUSHING) {\n observerList.forEach((o) => { o.next(newValue) })\n\n return\n }\n\n itemsToFlush.push(newValue)\n // observerList.forEach((o) => { o.next(newValue) })\n\n if (!isFlushing) {\n isFlushing = true\n void Promise.resolve().then(() => {\n observerList.forEach((o) => { o.next(itemsToFlush as T) })\n itemsToFlush = []\n isFlushing = false\n })\n }\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\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\n"],"names":["nonReactiveObjectSymbol","Symbol","deepClone","obj","newObj","Array","isArray","map","item","hasOwnProperty","Object","entries","forEach","_ref","value","getOwnPropertySymbols","symbol","isObject","hasOwn","call","bind","ROOT_VALUE","proxifyStore","store$$","objectToProxify","opts","_opts$nestedFieldPath","_objectWithRootValue","fieldPath","nestedFieldPath","objectWithRootValue","rootFunctions","fromEntries","filter","v","Proxy","get","targetObject","propName","receiver","target","propertyValue","Reflect","isValidElement","_opts$parentObjectToP","newNestedFieldPath","_$fieldPath","proxiedNestedObject","parentObjectToProxify","afterChange","set","parentObject","key","newValue","_opts$parentObjectToP2","_opts","isRootTarget","previousValue","JSON","stringify","_extends","next","storeValue","change","realInnerObject","$value","nextStoreChange","replace","has","t","p","ownKeys","getOwnPropertyDescriptor","cervello","initialValue","options","clonedInitialValue","createCacheableSubject","defaultValue","getValueOnSubscribe","isFlushing","observerList","getValue","itemsToFlush","push","resolve","then","o","subscribe","observer","unsubscribe","unSubscribeAll","proxiedStore","store","reset","useStore","_options$initialValue","_ref2","apply","isInitialValueSet","useRef","current","selectFieldPaths","select","selectedFieldPathsForNestedObjects","fp","includes","useLayoutEffect","setValueOnMount","err","console","error","useSyncExternalStore","onStoreChange","subscription","sc","storeChanges","onChange","some","nextChange","find","startsWith"],"mappings":"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"}
|
package/dist/cervello.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,
|
|
1
|
+
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],n):n((e||self).react={},e.react)}(this,function(e,n){var t=Symbol("nonReactiveObject");function r(){return r=Object.assign?Object.assign.bind():function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])}return e},r.apply(this,arguments)}function u(e){if(!e||"object"!=typeof e)return e;var n={};return Array.isArray(e)?n=e.map(function(e){return u(e)}):e.hasOwnProperty("$$typeof")?n=e:(Object.entries(e).forEach(function(e){n[e[0]]=u(e[1])}),Object.getOwnPropertySymbols(e).forEach(function(t){n[t]=u(e[t])})),n}var o=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)};"hasOwn"in Object||(Object.hasOwn=Object.call.bind(Object.hasOwnProperty));var i=Symbol("value");function a(e,l,f){var c,s;void 0===f&&(f={});var h=null!=(c=f.nestedFieldPath)?c:"root",v=((s={})[i]=l,s),y="root"===h?Object.fromEntries(Object.entries(l).filter(function(e){return"function"==typeof e[1]})):{};return new Proxy(v,{get:function(r,l,c){if("_$fieldPath"===l)return h;var s=Object.hasOwn(r,i)?r[i]:r;if("toJSON"===l)return function(){return s};if("$value"===l)return u(s);var v,y=Reflect.get(s,l,c);if("symbol"==typeof l)return y;if("function"==typeof y)return y.bind(c);if(o(v=y)&&!n.isValidElement(v)&&!v[t]){var b,p=h+"."+l;if(y._$fieldPath===p)return y;var d=a(e,y,{nestedFieldPath:p,parentObjectToProxify:null!=(b=f.parentObjectToProxify)?b:s,afterChange:f.afterChange});return s[l]=d}return y},set:function(u,a,l,c){var s,v;if("symbol"==typeof a)return!0;var b=l,p=Object.hasOwn(u,i);if(p&&"$value"===a){var d=u[i];return b===d||JSON.stringify(b)===JSON.stringify(u[i])||("root"!==h?u[i]=b:(u[i]=r({},y,b),e.next({storeValue:u[i],change:{fieldPath:"root",newValue:b,previousValue:d}}))),!0}var g=p?u[i]:u,O=Reflect.get(g,a,c);if(O===b)return!0;o(b)&&!n.isValidElement(b)&&!b[t]&&O._$fieldPath?O.$value=b:Reflect.set(g,a,b,g);var P={storeValue:null!=(s=null==(v=f)?void 0:v.parentObjectToProxify)?s:g,change:{fieldPath:(h+"."+a).replace("root.",""),newValue:b,previousValue:O}};return e.next(P),null==f.afterChange||f.afterChange([P]),!0},has:function(e,n){return Reflect.has(e[i],n)},ownKeys:function(e){return Reflect.ownKeys(e[i])},getOwnPropertyDescriptor:function(e,n){return Reflect.getOwnPropertyDescriptor(e[i],n)}})}e.cervello=function(e,t){var r=(null!=t?t:{}).afterChange,o=u(e),i=function(e,n){void 0===n&&(n=!1);var t=!1,r=[],u=[],o=e;return{getValue:function(){return o},next:function(e){o=e,r.push(e),t||(t=!0,Promise.resolve().then(function(){u.forEach(function(e){e.next(r)}),r=[],t=!1}))},subscribe:function(e){return n&&e.next(o),u.push(e),{unsubscribe:function(){u=u.filter(function(n){return n!==e})}}},unSubscribeAll:function(){u=[]}}}(o),l=a(i,o,{afterChange:r});return{store:l,reset:function(){l.$value=u(e)},useStore:function(e){var t,r,u=null==e||null==(t=e.initialValue)?void 0:t.apply(l,[l.$value]),o=n.useRef(!1);!o.current&&u&&u!==l&&(o.current=!0,l.$value=u);var a=n.useRef(null!=(r="function"==typeof(null==e?void 0:e.select)?null==e||null==e.select?void 0:e.select():null==e?void 0:e.select)?r:[]),f=n.useRef(a.current.filter(function(e){return e.includes(".*")}).map(function(e){return e.replace(".*","")}));return n.useLayoutEffect(function(){null!=e&&e.setValueOnMount&&e.setValueOnMount(l.$value).then(function(e){l.$value=e}).catch(function(e){console.error("Error setting initial value on mount",e)})},[]),n.useSyncExternalStore(function(n){var t=i.subscribe({next:function(t){var r=Array.isArray(t)?t:[t];if(null==e||!e.select)return n(),void(null==e||null==e.onChange||e.onChange(r));r.some(function(e){return"root"===e.change.fieldPath||a.current.includes(e.change.fieldPath)||f.current.find(function(n){return e.change.fieldPath.startsWith(n)})})&&(n(),null==e||null==e.onChange||e.onChange(r))}});return function(){t.unsubscribe()}},function(){return i.getValue()},function(){return i.getValue()}),l}}}});
|
|
2
2
|
//# sourceMappingURL=cervello.umd.js.map
|
package/dist/cervello.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cervello.umd.js","sources":["../src/lib/helpers/constants.ts","../src/lib/utils/object.ts","../src/lib/utils/string.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","\nexport function capitalize (str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport function isCamelCase (str: string): boolean {\n const regex = /^[a-z]+([A-Z][a-z]*)*$/\n\n return regex.test(str)\n}\n","\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { deepClone, isObject, okTarget } from '../utils'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol' && !Object.hasOwn(propertyValue, '$$typeof')) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol' && !Object.hasOwn(newValue, '$$typeof')) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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, useSyncExternalStore } from 'react'\n\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { contentComparer, deepClone, getPartialObjectFromProperties } from '../utils'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol.for('_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 >(\n type === 'full'\n ? null\n // To avoid the first render to be always different even\n // if store changed other than selected attributes\n : getPartialObjectFromProperties(selectors, (store$$.getValue() as any)?.[INTERNAL_VALUE_PROP]),\n )\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') {\n onStoreChange()\n\n return\n }\n\n // Partial store section ------------------------------------------------------------------\n const currentSlice = getPartialObjectFromProperties(selectors, (v as any)?.[INTERNAL_VALUE_PROP])\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n\n if (!isEquals) {\n /**\n * Update previous slice with deepClone to avoid storing direct store$$ value reference.\n * This solve reference/value problems when changing the store object\n * (proxy.set is changing the target object which is 'v' here)\n */\n prevSlice.current = deepClone(currentSlice)\n onStoreChange()\n }\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","\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 capitalize,\n isCamelCase,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ntype 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\ndeclare type Prettify<T> = {} & {\n [K in keyof T]: T[K];\n}\n\n\n\n\ntype CervelloStore<StoreType, StoreName extends string | undefined = undefined> =\n StoreName extends string\n ? Prettify<{\n // /** Reactive store */\n [K in `${StoreName}Store`]: StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Store`]: () => StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Selector`]: UseSelector<StoreType>\n }\n & {\n /** Resets the value to the initial value passed in */\n [K in `reset${Capitalize<StoreName>}Store`]: () => void\n }\n & {\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType, StoreName>\n }>\n :\n {\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, StoreName>\n }\n\n\nexport type CervelloOptions<StoreName extends string | undefined = undefined> = {\n name?: StoreName\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 - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT,\nStoreName extends string | undefined = undefined,\n> (initialValue: () => T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\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 \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT extends Record<string, unknown>,\nStoreName extends string | undefined = undefined,\n> (initialValue: T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\n\n\n\n/** @internal */\nexport function cervello <T, StoreName extends string | undefined = undefined> (\n initialValue: T | (() => T),\n options: CervelloOptions<StoreName> = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }, StoreName> {\n const { name: optionsName, reactiveNestedObjects = true } = options\n\n if (optionsName && !isCamelCase(optionsName))\n throw new Error(`[cervello]: options.name must be in camelCase and \"${optionsName}\" doesn't respect this rule.`)\n\n\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, reactiveNestedObjects)\n\n const cervelloStore = {\n [optionsName\n ? `${optionsName}Store`\n : 'store'\n ]: proxiedStore,\n\n [optionsName\n ? `reset${capitalize(optionsName)}Store`\n : 'reset'\n ] () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n [optionsName\n ? `use${capitalize(optionsName)}Store`\n : 'useStore'\n ]: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n\n [optionsName\n ? `use${capitalize(optionsName)}Selector`\n : 'useSelector'\n ]: 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\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\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n\n return this\n },\n } as any\n\n\n\n return cervelloStore\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\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","capitalize","str","charAt","toUpperCase","slice","hasOwn","call","bind","hasOwnProperty","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","_newClonedValue","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","_store$$$getValue","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","initialValue","options","reactiveNestedObjects","optionsName","name","_options$reactiveNest","test","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","value","o","observer","push","filter","unSubscribeAll","cervelloStore","$value","_cervelloStore","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cervello.umd.js","sources":["../src/types/shared.ts","../src/lib/utils/object.ts","../src/lib/helpers/new-proxify-store.ts","../src/lib/store/new-index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-types */\nexport type WithoutType<T, V, WithNever = {\n [K in keyof T]: Exclude<T[K], undefined> extends V\n ? never\n : (T[K] extends Record<string, unknown>\n ? WithoutType<T[K], V>\n : T[K])\n}> = Pick<WithNever, {\n [K in keyof WithNever]: WithNever[K] extends never ? never : K\n}[keyof WithNever]>\n\n\n\nexport type ObjectFromAttributes<T, Attributes extends Array< keyof WithoutType<T, Function> > > = {\n [k in Attributes[number]]: T[k]\n}\n\nexport type Maybe<T> = T | undefined\n\n\n\nexport type UseSelector<T> = <Attributes extends Array< Exclude<keyof WithoutType<T, Function>, '$value'> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n) => T\n\nexport type FieldPath<T extends Record<string, any>> = {\n [K in keyof Required<T>]: T[K] extends Record<string, any>\n ? K extends string\n\n ? T[K] extends Function\n ? never\n : T[K] extends Array<any>\n ? K\n : `${K}.*` | `${K}.${FieldPath<T[K]>}`\n : never\n : K extends string\n ? K\n : never\n}[keyof T]\n\nexport const nonReactiveObjectSymbol = Symbol('nonReactiveObject')\nexport type StoreChange<T extends Record<string, any>> = {\n change: {\n fieldPath: FieldPath<T>\n newValue: any\n previousValue: any\n }\n storeValue: T\n}\n","\nimport { 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\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n // eslint-disable-next-line no-prototype-builtins\n } else if (!obj.hasOwnProperty('$$typeof')) {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n Object.getOwnPropertySymbols(obj).forEach((symbol) => {\n newObj[symbol] = deepClone((obj as any)[symbol])\n })\n } else {\n newObj = obj\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\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n\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 { isValidElement } from 'react'\n\nimport { nonReactiveObjectSymbol } from '../../types/shared'\nimport { deepClone, isObject } from '../utils/object'\n\nimport type { StoreChange } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst ROOT_VALUE = Symbol('value')\n\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<StoreChange<T>>,\n objectToProxify: T,\n opts: {\n nestedFieldPath?: string\n parentObjectToProxify?: any\n // beforeChange?: (storeChange: StoreChange<T>) => any\n afterChange?: (storeChange: Array<StoreChange<T>>) => void\n } = {},\n): T {\n const fieldPath = opts.nestedFieldPath ?? 'root'\n\n const objectWithRootValue = {\n [ROOT_VALUE]: objectToProxify,\n } as unknown as T\n\n const rootFunctions = fieldPath === 'root'\n ? Object.fromEntries(Object.entries(objectToProxify).filter(([,v]) => typeof v === 'function'))\n : {}\n\n return new Proxy(objectWithRootValue, {\n get (targetObject, propName, receiver) {\n if (propName === '_$fieldPath') return fieldPath\n\n const isRootTarget = Object.hasOwn(targetObject, ROOT_VALUE)\n const target = isRootTarget ? targetObject[ROOT_VALUE] : targetObject\n\n if (propName === 'toJSON') return () => target\n\n if (propName === '$value') return deepClone(target)\n\n const propertyValue = Reflect.get(target, propName, receiver)\n\n if (typeof propName === 'symbol') return propertyValue\n\n\n if (typeof propertyValue === 'function')\n return (propertyValue as () => any).bind(receiver)\n\n\n if (isValidReactiveObject(propertyValue)) {\n const newNestedFieldPath = `${fieldPath}.${propName}`\n\n\n if (propertyValue._$fieldPath === newNestedFieldPath) return propertyValue\n\n const proxiedNestedObject = proxifyStore(\n store$$ as any,\n propertyValue,\n {\n nestedFieldPath: newNestedFieldPath,\n parentObjectToProxify: opts.parentObjectToProxify ?? target,\n // beforeChange: opts.beforeChange,\n afterChange: opts.afterChange,\n },\n )\n\n return target[propName] = proxiedNestedObject\n }\n\n return propertyValue\n },\n\n\n set (parentObject, key, newValue, receiver) {\n if (typeof key === 'symbol') return true\n\n const value = newValue\n const isRootTarget = Object.hasOwn(parentObject, ROOT_VALUE)\n\n if (isRootTarget && key === '$value') {\n const previousValue = parentObject[ROOT_VALUE]\n\n if (value === previousValue) return true\n if (JSON.stringify(value) === JSON.stringify(parentObject[ROOT_VALUE])) return true\n\n if (fieldPath !== 'root') {\n (parentObject as any)[ROOT_VALUE] = value\n } else {\n (parentObject as any)[ROOT_VALUE] = {\n ...rootFunctions,\n ...value,\n }\n store$$.next({\n // To be disabled for performance and send same store reference\n // storeValue: JSON.parse(JSON.stringify(targetObject[ROOT_VALUE])),\n storeValue: parentObject[ROOT_VALUE],\n change: {\n fieldPath: 'root' as any,\n newValue: value,\n previousValue,\n },\n })\n }\n\n return true\n }\n\n const realInnerObject = isRootTarget ? parentObject[ROOT_VALUE] : parentObject\n const previousValue = Reflect.get(realInnerObject, key, receiver)\n\n\n if (previousValue === value)\n return true\n\n\n // New object values, check if the field has already a proxy created to use it instead of reacreating a new instance\n if (isObject(value) && !isValidElement(value) && !value[nonReactiveObjectSymbol] && previousValue._$fieldPath)\n previousValue.$value = value\n else\n Reflect.set(realInnerObject, key, value, realInnerObject)\n\n\n const nextStoreChange = {\n // To be disabled for performance and send same store reference\n // storeValue: JSON.parse(JSON.stringify(opts?.parentObjectToProxify ?? target)),\n storeValue: opts?.parentObjectToProxify ?? realInnerObject,\n change: {\n fieldPath: `${fieldPath}.${key}`.replace('root.', '') as any,\n newValue: value,\n previousValue,\n },\n }\n\n store$$.next(nextStoreChange)\n opts.afterChange?.([nextStoreChange])\n\n return true\n },\n\n has (t, p) {\n return Reflect.has(t[ROOT_VALUE], p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(t[ROOT_VALUE])\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(t[ROOT_VALUE], p)\n },\n\n })\n}\n\n\nfunction isValidReactiveObject <T extends Record<string, any>> (value: T): boolean {\n return isObject(value) && !isValidElement(value) && !(value as any)[nonReactiveObjectSymbol]\n}\n","\nimport { useLayoutEffect, useRef, useSyncExternalStore } from 'react'\n\nimport { nonReactiveObjectSymbol } from '../../types/shared'\nimport { proxifyStore } from '../helpers/new-proxify-store'\nimport { deepClone } from '../utils/object'\nimport { createCacheableSubject } from '../utils/subject'\n\nimport type { FieldPath, StoreChange } from '../../types/shared'\n\n\n\n\n// export type CervelloOptions<StoreValue extends Record<string, any>> = {\n// beforeChange?: (storeChange: StoreChange<StoreValue>) => unknown | undefined\n// afterChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n// }\n\nexport type CervelloOptions<StoreValue extends Record<string, any>> = {\n afterChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n}\n\nexport type CervelloUseStoreOptions<StoreValue extends Record<string, any>> = {\n initialValue?: (currentStore: StoreValue) => StoreValue,\n setValueOnMount?: (currentStore: StoreValue) => Promise<StoreValue>,\n select?:\n | Array<FieldPath<StoreValue>>\n | (() => Array<FieldPath<StoreValue>>)\n onChange?: (storeChange: Array<StoreChange<StoreValue>>) => void\n}\n\ntype MutableStoreValue<T extends Record<string, any>> = {\n $value: T\n} & T\n\n\n\n\n\n\n\n\nexport function nonReactive <T extends Record<string, any>> (initialValue: T): T {\n Object.defineProperty(initialValue, nonReactiveObjectSymbol, {\n value: true,\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n return initialValue\n}\n\n\nexport function cervello <StoreValue extends Record<PropertyKey, any>> (\n initialValue: StoreValue,\n options?: CervelloOptions<StoreValue>,\n): {\n store: MutableStoreValue<StoreValue>,\n reset: () => void,\n useStore: (options?: CervelloUseStoreOptions<StoreValue>) => MutableStoreValue<StoreValue>\n } {\n const {\n // beforeChange,\n afterChange,\n } = options ?? {}\n\n const clonedInitialValue = deepClone(initialValue)\n const store$$ = createCacheableSubject<StoreChange<StoreValue>>(clonedInitialValue as any)\n\n const proxiedStore = proxifyStore(\n store$$ as any,\n clonedInitialValue,\n // { beforeChange, afterChange },\n { afterChange },\n ) as MutableStoreValue<StoreValue>\n\n\n return {\n store: proxiedStore,\n reset: () => {\n proxiedStore.$value = deepClone(initialValue)\n },\n useStore: (options) => {\n const initialValue = options?.initialValue?.apply(proxiedStore, [proxiedStore.$value])\n const isInitialValueSet = useRef(false)\n\n if (!isInitialValueSet.current && initialValue && initialValue !== proxiedStore) {\n isInitialValueSet.current = true\n proxiedStore.$value = initialValue\n }\n\n const selectFieldPaths = useRef(\n (typeof options?.select === 'function'\n ? options?.select?.()\n : options?.select)\n ?? [],\n )\n\n const selectedFieldPathsForNestedObjects = useRef(\n selectFieldPaths.current\n .filter(fp => fp.includes('.*'))\n .map(fp => fp.replace('.*', '')),\n )\n\n\n useLayoutEffect(() => {\n if (options?.setValueOnMount) {\n void options.setValueOnMount(proxiedStore.$value).then((value) => {\n proxiedStore.$value = value\n }).catch((err) => {\n console.error('Error setting initial value on mount', err)\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n\n useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (sc) => {\n const storeChanges = Array.isArray(sc)\n ? sc as Array<StoreChange<StoreValue>>\n : [sc]\n\n if (!options?.select) {\n onStoreChange()\n options?.onChange?.(storeChanges)\n\n return\n }\n\n if (storeChanges.some(nextChange => (\n nextChange.change.fieldPath === 'root'\n || selectFieldPaths.current.includes(nextChange.change.fieldPath))\n || selectedFieldPathsForNestedObjects.current.find(fp => nextChange.change.fieldPath.startsWith(fp)),\n )) {\n onStoreChange()\n options?.onChange?.(storeChanges)\n }\n },\n })\n\n return () => {\n subscription.unsubscribe()\n }\n },\n () => store$$.getValue(),\n () => store$$.getValue(),\n )\n\n return proxiedStore\n },\n }\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\nconst WITH_FLUSHING = true\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = false): CacheableSubject<T> {\n let isFlushing = false\n let itemsToFlush: Array<T> = []\n\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\n if (!WITH_FLUSHING) {\n observerList.forEach((o) => { o.next(newValue) })\n\n return\n }\n\n itemsToFlush.push(newValue)\n // observerList.forEach((o) => { o.next(newValue) })\n\n if (!isFlushing) {\n isFlushing = true\n void Promise.resolve().then(() => {\n observerList.forEach((o) => { o.next(itemsToFlush as T) })\n itemsToFlush = []\n isFlushing = false\n })\n }\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\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\n"],"names":["nonReactiveObjectSymbol","Symbol","deepClone","obj","newObj","Array","isArray","map","item","hasOwnProperty","Object","entries","forEach","_ref","value","getOwnPropertySymbols","symbol","isObject","hasOwn","call","bind","ROOT_VALUE","proxifyStore","store$$","objectToProxify","opts","_opts$nestedFieldPath","_objectWithRootValue","fieldPath","nestedFieldPath","objectWithRootValue","rootFunctions","fromEntries","filter","v","Proxy","get","targetObject","propName","receiver","target","propertyValue","Reflect","isValidElement","_opts$parentObjectToP","newNestedFieldPath","_$fieldPath","proxiedNestedObject","parentObjectToProxify","afterChange","set","parentObject","key","newValue","_opts$parentObjectToP2","_opts","isRootTarget","previousValue","JSON","stringify","_extends","next","storeValue","change","realInnerObject","$value","nextStoreChange","replace","has","t","p","ownKeys","getOwnPropertyDescriptor","cervello","initialValue","options","clonedInitialValue","createCacheableSubject","defaultValue","getValueOnSubscribe","isFlushing","observerList","getValue","itemsToFlush","push","resolve","then","o","subscribe","observer","unsubscribe","unSubscribeAll","proxiedStore","store","reset","useStore","_options$initialValue","_ref2","apply","isInitialValueSet","useRef","current","selectFieldPaths","select","selectedFieldPathsForNestedObjects","fp","includes","useLayoutEffect","setValueOnMount","err","console","error","useSyncExternalStore","onStoreChange","subscription","sc","storeChanges","onChange","some","nextChange","find","startsWith"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cervello/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
5
|
-
"description": "π€―
|
|
4
|
+
"version": "5.0.0-beta.2",
|
|
5
|
+
"description": "π€― Simple, reactive, tiny and performant state-management library",
|
|
6
6
|
"author": "Chempo",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"homepage": "https://www.cervello.dev",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"state",
|
|
19
19
|
"manager",
|
|
20
20
|
"management",
|
|
21
|
+
"proxy",
|
|
21
22
|
"redux",
|
|
22
23
|
"zustand",
|
|
23
24
|
"reactive",
|
|
@@ -31,13 +32,12 @@
|
|
|
31
32
|
"exports": {
|
|
32
33
|
".": {
|
|
33
34
|
"types": "./types/index.d.ts",
|
|
34
|
-
"browser": "./dist/cervello.esm.js",
|
|
35
35
|
"require": "./dist/cervello.cjs",
|
|
36
36
|
"import": "./dist/cervello.esm.js",
|
|
37
|
-
"
|
|
38
|
-
"default": "./dist/cervello.modern.js"
|
|
37
|
+
"default": "./dist/cervello.esm.js"
|
|
39
38
|
},
|
|
40
39
|
"./types": {
|
|
40
|
+
"types": "./types/index.d.ts",
|
|
41
41
|
"browser": "./types/index.d.ts",
|
|
42
42
|
"require": "./types/index.d.ts",
|
|
43
43
|
"import": "./types/index.d.ts",
|
|
@@ -46,13 +46,22 @@
|
|
|
46
46
|
},
|
|
47
47
|
"main": "./dist/cervello.cjs",
|
|
48
48
|
"module": "./dist/cervello.esm.js",
|
|
49
|
-
"unpkg": "./dist/cervello.umd.js",
|
|
50
49
|
"source": "src/index.ts",
|
|
51
50
|
"types": "./types/index.d.ts",
|
|
52
51
|
"files": [
|
|
53
52
|
"dist",
|
|
54
53
|
"types"
|
|
55
54
|
],
|
|
55
|
+
"scripts": {
|
|
56
|
+
"release": "pnpx bumpp --push=false && npm publish --access public",
|
|
57
|
+
"docs:dev": "pnpm run --filter @cervello/react docs:dev",
|
|
58
|
+
"publish:beta": "npm publish --tag beta",
|
|
59
|
+
"test": "vitest --watch",
|
|
60
|
+
"test:release": "vitest run",
|
|
61
|
+
"prepublishOnly": "pnpm build",
|
|
62
|
+
"build": "(rm -rf types & rm -rf dist) && microbundle",
|
|
63
|
+
"dev": "microbundle watch"
|
|
64
|
+
},
|
|
56
65
|
"peerDependencies": {
|
|
57
66
|
"react": ">= 18.2.0"
|
|
58
67
|
},
|
|
@@ -62,16 +71,9 @@
|
|
|
62
71
|
"@types/react": "18.2.33",
|
|
63
72
|
"microbundle": "0.15.1",
|
|
64
73
|
"react": "18.2.0",
|
|
65
|
-
"typescript": "5.
|
|
74
|
+
"typescript": "5.6.2",
|
|
66
75
|
"vite": "4.5.0",
|
|
67
|
-
"vitest": "0.
|
|
76
|
+
"vitest": "3.0.7",
|
|
68
77
|
"vitest-react": "0.9.5"
|
|
69
|
-
},
|
|
70
|
-
"scripts": {
|
|
71
|
-
"release": "pnpx bumpp --push=false && npm publish --access public",
|
|
72
|
-
"test": "vitest --watch",
|
|
73
|
-
"test:release": "vitest run",
|
|
74
|
-
"build": "(rm -rf types & rm -rf dist) && microbundle",
|
|
75
|
-
"dev": "microbundle watch"
|
|
76
78
|
}
|
|
77
|
-
}
|
|
79
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { cervello } from './lib/store';
|
|
2
|
-
export type {
|
|
1
|
+
export { cervello } from './lib/store/new-index';
|
|
2
|
+
export type { CervelloOptions, CervelloUseStoreOptions } from './lib/store/new-index';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { StoreChange } from '../../types/shared';
|
|
2
|
+
import type { CacheableSubject } from '../utils/subject';
|
|
3
|
+
export declare function proxifyStore<T extends Record<string | symbol, any>>(store$$: CacheableSubject<StoreChange<T>>, objectToProxify: T, opts?: {
|
|
4
|
+
nestedFieldPath?: string;
|
|
5
|
+
parentObjectToProxify?: any;
|
|
6
|
+
afterChange?: (storeChange: Array<StoreChange<T>>) => void;
|
|
7
|
+
}): T;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FieldPath, StoreChange } from '../../types/shared';
|
|
2
|
+
export type CervelloOptions<StoreValue extends Record<string, any>> = {
|
|
3
|
+
afterChange?: (storeChange: Array<StoreChange<StoreValue>>) => void;
|
|
4
|
+
};
|
|
5
|
+
export type CervelloUseStoreOptions<StoreValue extends Record<string, any>> = {
|
|
6
|
+
initialValue?: (currentStore: StoreValue) => StoreValue;
|
|
7
|
+
setValueOnMount?: (currentStore: StoreValue) => Promise<StoreValue>;
|
|
8
|
+
select?: Array<FieldPath<StoreValue>> | (() => Array<FieldPath<StoreValue>>);
|
|
9
|
+
onChange?: (storeChange: Array<StoreChange<StoreValue>>) => void;
|
|
10
|
+
};
|
|
11
|
+
type MutableStoreValue<T extends Record<string, any>> = {
|
|
12
|
+
$value: T;
|
|
13
|
+
} & T;
|
|
14
|
+
export declare function nonReactive<T extends Record<string, any>>(initialValue: T): T;
|
|
15
|
+
export declare function cervello<StoreValue extends Record<PropertyKey, any>>(initialValue: StoreValue, options?: CervelloOptions<StoreValue>): {
|
|
16
|
+
store: MutableStoreValue<StoreValue>;
|
|
17
|
+
reset: () => void;
|
|
18
|
+
useStore: (options?: CervelloUseStoreOptions<StoreValue>) => MutableStoreValue<StoreValue>;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
package/types/types/shared.d.ts
CHANGED
|
@@ -8,3 +8,15 @@ export type ObjectFromAttributes<T, Attributes extends Array<keyof WithoutType<T
|
|
|
8
8
|
};
|
|
9
9
|
export type Maybe<T> = T | undefined;
|
|
10
10
|
export 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;
|
|
11
|
+
export type FieldPath<T extends Record<string, any>> = {
|
|
12
|
+
[K in keyof Required<T>]: T[K] extends Record<string, any> ? K extends string ? T[K] extends Function ? never : T[K] extends Array<any> ? K : `${K}.*` | `${K}.${FieldPath<T[K]>}` : never : K extends string ? K : never;
|
|
13
|
+
}[keyof T];
|
|
14
|
+
export declare const nonReactiveObjectSymbol: unique symbol;
|
|
15
|
+
export type StoreChange<T extends Record<string, any>> = {
|
|
16
|
+
change: {
|
|
17
|
+
fieldPath: FieldPath<T>;
|
|
18
|
+
newValue: any;
|
|
19
|
+
previousValue: any;
|
|
20
|
+
};
|
|
21
|
+
storeValue: T;
|
|
22
|
+
};
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2021 Chempo GonzΓ‘lez
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|