@ -9,38 +9,21 @@ import {
object _prototype
} from '../shared/utils.js' ;
import { state as source , set } from './reactivity/sources.js' ;
import {
PROXY _CHANGE _PATH ,
PROXY _PATH _SYMBOL ,
PROXY _PRESERVE _PATH ,
PROXY _REMOVE _PATH ,
STATE _SYMBOL
} from '#client/constants' ;
import { PROXY _PATH _SYMBOL , STATE _SYMBOL } from '#client/constants' ;
import { UNINITIALIZED } from '../../constants.js' ;
import * as e from './errors.js' ;
import { get _stack , tag } from './dev/tracing.js' ;
import { tracing _mode _flag } from '../flags/index.js' ;
// TODO move all regexes into shared module?
const regex _is _valid _identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/ ;
/ * *
* @ template T
* @ param { T } value
* @ param { string } [ path ]
* @ param { number } [ path _preservation ]
* @ returns { T }
* /
export function proxy ( value , path , path _preservation = PROXY _PRESERVE _PATH ) {
// if `DEV`, change the proxy `path` since we don't know if its still "owned" by its original source
if (
DEV &&
( path _preservation & PROXY _PRESERVE _PATH ) === 0 &&
typeof value === 'object' &&
value !== null &&
STATE _SYMBOL in value &&
PROXY _PATH _SYMBOL in value
) {
value [ PROXY _PATH _SYMBOL ] =
( path _preservation & PROXY _CHANGE _PATH ) === 0 ? '[$state proxy]' : path ;
}
export function proxy ( value ) {
// if non-proxyable, or is already a proxy, return `value`
if ( typeof value !== 'object' || value === null || STATE _SYMBOL in value ) {
return value ;
@ -55,20 +38,10 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
/** @type {Map<any, Source<any>>} */
var sources = new Map ( ) ;
var is _proxied _array = is _array ( value ) ;
var version = DEV ? tag ( source ( 0 ) , ` ${ path } version ` ) : source( 0 ) ;
var version = source( 0 ) ;
var stack = DEV && tracing _mode _flag ? get _stack ( 'CreatedAt' ) : null ;
var reaction = active _reaction ;
/** @type {(prop: any) => any} */
var to _trace _name = DEV
? ( prop ) => {
return typeof prop === 'symbol'
? ` ${ path } [Symbol( ${ prop . description ? ? '' } )] `
: typeof prop === 'number' || Number ( prop ) === Number ( prop )
? ` ${ path } [ ${ prop } ] `
: ` ${ path } . ${ prop } ` ;
}
: ( prop ) => undefined ;
/ * *
* @ template T
@ -88,8 +61,22 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
if ( is _proxied _array ) {
// We need to create the length source eagerly to ensure that
// mutations to the array are properly synced with our proxy
const length _source = source ( /** @type {any[]} */ ( value ) . length , stack ) ;
sources . set ( 'length' , DEV ? tag ( length _source , to _trace _name ( 'length' ) ) : length _source ) ;
sources . set ( 'length' , source ( /** @type {any[]} */ ( value ) . length , stack ) ) ;
}
/** Used in dev for $inspect.trace() */
var path = '' ;
/** @param {string} new_path */
function update _path ( new _path ) {
path = new _path ;
tag ( version , ` ${ path } version ` ) ;
// rename all child sources and child proxies
for ( const [ prop , source ] of sources ) {
tag ( source , get _label ( path , prop ) ) ;
}
}
return new Proxy ( /** @type {any} */ ( value ) , {
@ -107,18 +94,20 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
e . state _descriptors _fixed ( ) ;
}
with _parent ( ( ) => {
var s = sources . get ( prop ) ;
if ( s === undefined ) {
s = with _parent ( ( ) => source ( descriptor . value , stack ) ) ;
s = DEV && typeof prop === 'string' ? tag ( s , to _trace _name ( prop ) ) : s ;
s = source ( descriptor . value , stack ) ;
sources . set ( prop , s ) ;
if ( DEV && typeof prop === 'string' ) {
tag ( s , get _label ( path , prop ) ) ;
}
} else {
set (
s ,
with _parent ( ( ) => proxy ( descriptor . value , to _trace _name ( prop ) ) )
) ;
set ( s , descriptor . value , true ) ;
}
} ) ;
return true ;
} ,
@ -129,8 +118,12 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
if ( s === undefined ) {
if ( prop in target ) {
const s = with _parent ( ( ) => source ( UNINITIALIZED , stack ) ) ;
sources . set ( prop , DEV ? tag ( s , to _trace _name ( prop ) ) : s) ;
sources . set ( prop , s) ;
update _version ( version ) ;
if ( DEV ) {
tag ( s , get _label ( path , prop ) ) ;
}
}
} else {
// When working with arrays, we need to also ensure we update the length when removing
@ -154,8 +147,9 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
if ( prop === STATE _SYMBOL ) {
return value ;
}
if ( DEV && prop === PROXY _PATH _SYMBOL ) {
return path;
return update_ path;
}
var s = sources . get ( prop ) ;
@ -163,10 +157,17 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
// create a source, but only if it's an own property and not a prototype property
if ( s === undefined && ( ! exists || get _descriptor ( target , prop ) ? . writable ) ) {
s = with _parent ( ( ) =>
source ( proxy ( exists ? target [ prop ] : UNINITIALIZED , to _trace _name ( prop ) ) , stack )
) ;
s = DEV ? tag ( s , to _trace _name ( prop ) ) : s ;
s = with _parent ( ( ) => {
var p = proxy ( exists ? target [ prop ] : UNINITIALIZED ) ;
var s = source ( p , stack ) ;
if ( DEV ) {
tag ( s , get _label ( path , prop ) ) ;
}
return s ;
} ) ;
sources . set ( prop , s ) ;
}
@ -202,7 +203,7 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
} ,
has ( target , prop ) {
if ( prop === STATE _SYMBOL || ( DEV && prop === PROXY _PATH _SYMBOL ) ) {
if ( prop === STATE _SYMBOL ) {
return true ;
}
@ -214,10 +215,17 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
( active _effect !== null && ( ! has || get _descriptor ( target , prop ) ? . writable ) )
) {
if ( s === undefined ) {
s = with _parent ( ( ) =>
source ( has ? proxy ( target [ prop ] , to _trace _name ( prop ) ) : UNINITIALIZED , stack )
) ;
s = DEV ? tag ( s , to _trace _name ( prop ) ) : s ;
s = with _parent ( ( ) => {
var p = has ? proxy ( target [ prop ] ) : UNINITIALIZED ;
var s = source ( p , stack ) ;
if ( DEV ) {
tag ( s , get _label ( path , prop ) ) ;
}
return s ;
} ) ;
sources . set ( prop , s ) ;
}
@ -231,17 +239,6 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
} ,
set ( target , prop , value , receiver ) {
if ( DEV && prop === PROXY _PATH _SYMBOL ) {
path = value ;
tag ( version , ` ${ path } version ` ) ;
// rename all child sources and child proxies
for ( const [ prop , source ] of sources ) {
tag ( source , to _trace _name ( prop ) ) ;
if ( typeof source . v === 'object' && source . v !== null && PROXY _PATH _SYMBOL in source . v ) {
source . v [ PROXY _PATH _SYMBOL ] = to _trace _name ( prop ) ;
}
}
}
var s = sources . get ( prop ) ;
var has = prop in target ;
@ -256,8 +253,11 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
// else a later read of the property would result in a source being created with
// the value of the original item at that index.
other _s = with _parent ( ( ) => source ( UNINITIALIZED , stack ) ) ;
other _s = DEV ? tag ( other _s , to _trace _name ( i ) ) : other _s ;
sources . set ( i + '' , other _s ) ;
if ( DEV ) {
tag ( other _s , get _label ( path , i ) ) ;
}
}
}
}
@ -268,20 +268,23 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
// object property before writing to that property.
if ( s === undefined ) {
if ( ! has || get _descriptor ( target , prop ) ? . writable ) {
s = with _parent ( ( ) => source ( undefined , stack ) ) ;
s = DEV ? tag ( s , to _trace _name ( prop ) ) : s ;
set (
s ,
with _parent ( ( ) => proxy ( value , to _trace _name ( prop ) , PROXY _CHANGE _PATH ) )
) ;
s = with _parent ( ( ) => {
var s = source ( undefined , stack ) ;
set ( s , proxy ( value ) ) ;
return s ;
} ) ;
sources . set ( prop , s ) ;
if ( DEV ) {
tag ( s , get _label ( path , prop ) ) ;
}
}
} else {
has = s . v !== UNINITIALIZED ;
set (
s ,
with _parent ( ( ) => proxy ( value , to _trace _name ( prop ) , PROXY _CHANGE _PATH ) )
) ;
var p = with _parent ( ( ) => proxy ( value ) ) ;
set ( s , p ) ;
}
var descriptor = Reflect . getOwnPropertyDescriptor ( target , prop ) ;
@ -334,6 +337,16 @@ export function proxy(value, path, path_preservation = PROXY_PRESERVE_PATH) {
} ) ;
}
/ * *
* @ param { string } path
* @ param { string | symbol } prop
* /
function get _label ( path , prop ) {
if ( typeof prop === 'symbol' ) return ` ${ path } [Symbol( ${ prop . description ? ? '' } )] ` ;
if ( regex _is _valid _identifier . test ( prop ) ) return ` ${ path } . ${ prop } ` ;
return /^\d+$/ . test ( prop ) ? ` ${ path } [ ${ prop } ] ` : ` ${ path } [' ${ prop } '] ` ;
}
/ * *
* @ param { Source < number > } signal
* @ param { 1 | - 1 } [ d ]