@ -14,14 +14,14 @@ export const NOTIFY_WITH_ALL_PARAMS = Symbol();
* - DO NOT USE INTERCEPTORS FOR READ PROPERTIES
* - DO NOT USE INTERCEPTORS FOR READ PROPERTIES
* @ template TEntityInstance
* @ template TEntityInstance
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] } TReadProperties
* @ template { ( keyof TEntityInstance ) [ ] | undefined } TReadProperties
* @ typedef { Partial < Record < TWriteProperties [ number ] , ( notify _read _methods : ( methods : TReadProperties , ... params : unknown [ ] ) => void , value : TEntityInstance , property : TWriteProperties [ number ] , ... params : unknown [ ] ) => boolean >> } Interceptors
* @ typedef { Partial < Record < TWriteProperties [ number ] , ( notify _read _methods : ( methods : TReadProperties , ... params : unknown [ ] ) => void , value : TEntityInstance , property : TWriteProperties [ number ] , ... params : unknown [ ] ) => boolean >> } Interceptors
* /
* /
/ * *
/ * *
* @ template TEntityInstance
* @ template TEntityInstance
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] } TReadProperties
* @ template { ( keyof TEntityInstance ) [ ] | undefined } TReadProperties
* @ typedef { object } Options
* @ typedef { object } Options
* @ prop { TWriteProperties } write _properties - an array of property names on ` TEntityInstance ` , could cause reactivity .
* @ prop { TWriteProperties } write _properties - an array of property names on ` TEntityInstance ` , could cause reactivity .
* @ prop { TReadProperties } [ read _properties ] - an array of property names on ` TEntityInstance ` that ` write_properties ` affect , typically used for methods . for instance ` size ` doesn ' t need to be here because it takes no parameters and is reactive based on the ` version ` signal .
* @ prop { TReadProperties } [ read _properties ] - an array of property names on ` TEntityInstance ` that ` write_properties ` affect , typically used for methods . for instance ` size ` doesn ' t need to be here because it takes no parameters and is reactive based on the ` version ` signal .
@ -33,7 +33,7 @@ export const NOTIFY_WITH_ALL_PARAMS = Symbol();
/ * *
/ * *
* @ template { new ( ... args : any ) => any } TEntity
* @ template { new ( ... args : any ) => any } TEntity
* @ template { ( keyof InstanceType < TEntity > ) [ ] } TWriteProperties
* @ template { ( keyof InstanceType < TEntity > ) [ ] } TWriteProperties
* @ template { ( keyof InstanceType < TEntity > ) [ ] } TReadProperties
* @ template { ( keyof InstanceType < TEntity > ) [ ] | undefined } TReadProperties
* @ param { TEntity } Entity - the entity we want to make reactive
* @ param { TEntity } Entity - the entity we want to make reactive
* @ param { Options < InstanceType < TEntity > , TWriteProperties , TReadProperties > } options - configurations for how reactivity works for this entity
* @ param { Options < InstanceType < TEntity > , TWriteProperties , TReadProperties > } options - configurations for how reactivity works for this entity
* @ returns { TEntity }
* @ returns { TEntity }
@ -50,7 +50,7 @@ export const make_reactive = (Entity, options) => {
* each read method can be tracked like has , get , has and etc . these props might depend on a parameter . they have to reactive based on the
* each read method can be tracked like has , get , has and etc . these props might depend on a parameter . they have to reactive based on the
* parameter they depend on . for instance if you have ` set.has(2) ` and then call ` set.add(5) ` the former shouldn ' t get notified .
* parameter they depend on . for instance if you have ` set.has(2) ` and then call ` set.add(5) ` the former shouldn ' t get notified .
* based on that we need to store the function _name + parameter ( s ) .
* based on that we need to store the function _name + parameter ( s ) .
* @ type { Map< string | symbol , Map < unknown [ ] , import ( "#client" ) . Source < boolean >>> }
* @ type { ReadMethodsSignals }
* * /
* * /
const read _methods _signals = new Map ( ) ;
const read _methods _signals = new Map ( ) ;
/ * *
/ * *
@ -73,23 +73,31 @@ export const make_reactive = (Entity, options) => {
options ,
options ,
... params
... params
) ;
) ;
const result = orig _property . bind ( target ) ( ... params ) ;
const function _result = orig _property . bind ( target ) ( ... params ) ;
// causing reactivity after the function is actually called and performed its changes
get _read _signals ( version _signal , read _methods _signals , property , options , ... params ) ;
notifiers . forEach ( ( notifier ) => notifier ( ) ) ;
notifiers . forEach ( ( notifier ) => notifier ( ) ) ;
return result ;
return function_ result;
} ) . bind ( target ) ;
} ) . bind ( target ) ;
} else {
} else {
// handle getters/props
// handle getters/props
result = Reflect . get ( target , property , target ) ;
get _read _signals ( version _signal , read _methods _signals , property , options , ... params ) ;
}
return result ;
} ,
set ( target , property , value ) {
const notifiers = create _notifiers (
const notifiers = create _notifiers (
version _signal ,
version _signal ,
read _methods _signals ,
read _methods _signals ,
property ,
property ,
target ,
target ,
options
options ,
value
) ;
) ;
result = Reflect . g et( target , property , target ) ;
const result = Reflect . s et( target , property , value , target ) ;
notifiers . forEach ( ( notifier ) => notifier ( ) ) ;
notifiers . forEach ( ( notifier ) => notifier ( ) ) ;
}
return result ;
return result ;
} ,
} ,
ownKeys : ( target ) => {
ownKeys : ( target ) => {
@ -106,7 +114,7 @@ export const make_reactive = (Entity, options) => {
* creates an array of functions that notify other signals based on the changes , you need to run these functions to invoke reactivity
* creates an array of functions that notify other signals based on the changes , you need to run these functions to invoke reactivity
* @ template { new ( ... args : any ) => any } TEntity
* @ template { new ( ... args : any ) => any } TEntity
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] } TReadProperties
* @ template { ( keyof TEntityInstance ) [ ] | undefined } TReadProperties
* @ template { InstanceType < TEntity > } TEntityInstance
* @ template { InstanceType < TEntity > } TEntityInstance
* @ template { keyof TEntityInstance } TProperty
* @ template { keyof TEntityInstance } TProperty
* @ param { import ( '#client' ) . Source < boolean > } version _signal
* @ param { import ( '#client' ) . Source < boolean > } version _signal
@ -133,7 +141,11 @@ function create_notifiers(
* /
* /
const notifiers = [ ] ;
const notifiers = [ ] ;
const interceptor = options . interceptors ? . [ property ] ;
const interceptor =
options . interceptors &&
Object . hasOwn ( options . interceptors , property ) &&
options . interceptors ? . [ property ] ;
if ( interceptor ) {
if ( interceptor ) {
const increment _version _signal =
const increment _version _signal =
interceptor (
interceptor (
@ -161,26 +173,42 @@ function create_notifiers(
notifiers . push ( ( ) => {
notifiers . push ( ( ) => {
if ( options . write _properties . some ( ( v ) => v === property ) ) {
if ( options . write _properties . some ( ( v ) => v === property ) ) {
increment _signal ( options _with _version _flag , version _signal ) ;
increment _signal ( options _with _version _flag , version _signal ) ;
} else {
}
} ) ;
return notifiers ;
}
/ * *
* @ template { new ( ... args : any ) => any } TEntity
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] | undefined } TReadProperties
* @ template { InstanceType < TEntity > } TEntityInstance
* @ template { keyof TEntityInstance } TProperty
* @ param { import ( '#client' ) . Source < boolean > } version _signal
* @ param { ReadMethodsSignals } read _methods _signals
* @ param { TProperty } property
* @ param { Options < InstanceType < TEntity > , TWriteProperties , TReadProperties > } options
* @ param { unknown [ ] } params
* /
function get _read _signals ( version _signal , read _methods _signals , property , options , ... params ) {
if ( options . read _properties ? . includes ( property ) ) {
if ( options . read _properties ? . includes ( property ) ) {
( params . length == 0 ? [ null ] : params ) . forEach ( ( param ) => {
( params . length == 0 ? [ null ] : params ) . forEach ( ( param ) => {
// read like methods should create the signal (if not already created) so they can be reactive when notified based on their param
// read like methods that are reactive conditionally should create the signal (if not already created) so they can be reactive when notified based on their param
const sig = get _signal _for _function ( read _methods _signals , property , param , true ) ;
const sig = get _signal _for _function ( read _methods _signals , property , param , true ) ;
get ( sig ) ;
get ( sig ) ;
} ) ;
} ) ;
} else {
} else {
// other read like methods that are not reactive conditionally based their params and are just notified based on the version signal are here
get ( version _signal ) ;
get ( version _signal ) ;
}
}
}
}
} ) ;
return notifiers ;
}
/ * *
/ * *
* @ template { new ( ... args : any ) => any } TEntity
* @ template { new ( ... args : any ) => any } TEntity
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] } TWriteProperties
* @ template { ( keyof TEntityInstance ) [ ] } TReadProperties
* @ template { ( keyof TEntityInstance ) [ ] | undefined } TReadProperties
* @ template { InstanceType < TEntity > } TEntityInstance
* @ template { InstanceType < TEntity > } TEntityInstance
* @ param { import ( '#client' ) . Source < boolean > } version _signal
* @ param { import ( '#client' ) . Source < boolean > } version _signal
* @ param { ReadMethodsSignals } read _methods _signals
* @ param { ReadMethodsSignals } read _methods _signals
@ -195,7 +223,7 @@ function notify_read_methods(
method _names ,
method _names ,
... params
... params
) {
) {
method _names . forEach ( ( name ) => {
method _names ? . forEach ( ( name ) => {
if ( DEV && ! options . read _properties ? . includes ( name ) ) {
if ( DEV && ! options . read _properties ? . includes ( name ) ) {
throw new Error (
throw new Error (
` when trying to notify reactions got a read method that wasn't defined in options: ${ name . toString ( ) } `
` when trying to notify reactions got a read method that wasn't defined in options: ${ name . toString ( ) } `