@ -3,7 +3,7 @@
/** @import { Store } from '#shared' */
export { FILENAME , HMR } from '../../constants.js' ;
import { attr , clsx , to _class , to _style } from '../shared/attributes.js' ;
import { is_promise , noop } from '../shared/utils.js' ;
import { get_descriptor _in _chain , is_promise , noop } from '../shared/utils.js' ;
import { subscribe _to _store } from '../../store/utils.js' ;
import {
UNINITIALIZED ,
@ -181,23 +181,57 @@ export function attributes(attrs, css_hash, classes, styles, flags = 0) {
export function spread _props ( props ) {
/** @type {Record<string, unknown>} */
const merged _props = { } ;
let key ;
for ( let i = 0 ; i < props . length ; i ++ ) {
const obj = props [ i ] ;
if ( obj == null ) continue ;
for ( key of Object . keys ( obj ) ) {
const desc = Object . getOwnPropertyDescriptor ( obj , key ) ;
if ( desc ) {
Object . defineProperty ( merged _props , key , desc ) ;
} else {
merged _props [ key ] = obj [ key ] ;
// `for..in` collects own + inherited enumerable string keys; class accessors
// aren't enumerable so we follow up with a prototype walk (excluding Object.prototype).
/** @type {Set<string>} */
const seen = new Set ( ) ;
for ( const key in obj ) {
seen . add ( key ) ;
copy _prop ( merged _props , obj , key ) ;
}
let proto = Object . getPrototypeOf ( obj ) ;
while ( proto != null && proto !== Object . prototype ) {
for ( const key of Object . getOwnPropertyNames ( proto ) ) {
if ( key === 'constructor' || seen . has ( key ) ) continue ;
seen . add ( key ) ;
copy _prop ( merged _props , obj , key ) ;
}
proto = Object . getPrototypeOf ( proto ) ;
}
}
return merged _props ;
}
/ * *
* Copies a property from ` source ` to ` target ` . Accessors are bound to ` source `
* so ` this ` resolves correctly when reading / writing through ` target ` ( relevant
* for class instances spread into props ) .
* @ param { Record < string , unknown > } target
* @ param { Record < string , unknown > } source
* @ param { string } key
* /
function copy _prop ( target , source , key ) {
const desc = get _descriptor _in _chain ( source , key ) ;
if ( ! desc ) {
target [ key ] = source [ key ] ;
return ;
}
if ( desc . get || desc . set ) {
Object . defineProperty ( target , key , {
enumerable : true ,
configurable : true ,
get : desc . get && desc . get . bind ( source ) ,
set : desc . set && desc . set . bind ( source )
} ) ;
} else {
Object . defineProperty ( target , key , desc ) ;
}
}
/ * *
* @ param { unknown } value
* @ returns { string }
@ -394,7 +428,7 @@ export function bind_props(props_parent, props_now) {
if (
initial _value === undefined &&
value !== undefined &&
Object . getOwnPropertyDescriptor ( props _parent , key ) ? . set
get _descriptor _in _chain ( props _parent , key ) ? . set
) {
props _parent [ key ] = value ;
}