@@ -2,6 +2,7 @@ import {untrackedCallback} from '@solid-devtools/shared/primitives'
22import { ObjectType , getSdtId } from '../main/id.ts'
33import { observeComputationUpdate } from '../main/observe.ts'
44import {
5+ type ElementChildren ,
56 type ElementInterface ,
67 type Mapped ,
78 type NodeID ,
@@ -214,8 +215,6 @@ export type TreeWalkerConfig<TEl extends object> = {
214215 eli : ElementInterface < TEl >
215216}
216217
217- const ElementsMap = new Map < Mapped . Owner , { el : object ; component : Mapped . Owner } > ( )
218-
219218const $WALKER = Symbol ( 'tree-walker' )
220219
221220function observeComputation < TEl extends object > (
@@ -273,68 +272,33 @@ function pushResolvedElements<TEl extends object>(list: TEl[], value: unknown, e
273272 }
274273}
275274
276- let MappedOwnerNode : Mapped . Owner
277- let AddedToParentElements = false
278-
279275/**
280- * @param els elements to map
281- * @param parent_children parent owner children.
282- * Will be checked for existing elements, and if found, `MappedOwnerNode` will be injected in the place of the element.
283- * Passing `undefined` will skip this check.
276+ * Updates a map of Element to Component_Owner by traversing the owner tree
277+ *
278+ * @param owner owner to start traversal from
279+ * @param eli Element interface
280+ * @param map Optional existing map to update
281+ *
282+ * The elements are resolved shallowly,
283+ * so only top-level elements will be mapped to their components.
284284 */
285- function mapElements < TEl extends object > (
286- els : Iterable < TEl > ,
287- parent_children : Mapped . Owner [ ] | undefined ,
288- eli : ElementInterface < TEl > ,
289- out : Mapped . Owner [ ] = [ ] ,
290- ) : Mapped . Owner [ ] {
291-
292- els: for ( let el of els ) {
293- if ( ! eli . isElement ( el ) ) continue
294-
295- if ( parent_children ) {
296-
297- // find el in parent els and remove it
298- let to_check = [ parent_children ]
299- let index = 0
300- let el_nodes = to_check [ index ++ ]
301-
302- while ( el_nodes ) {
303- for ( let i = 0 ; i < el_nodes . length ; i ++ ) {
304- let el_node = el_nodes [ i ] !
305- let el_node_data = ElementsMap . get ( el_node )
306- if ( el_node_data && el_node_data . el === el ) {
307- if ( AddedToParentElements ) {
308- // if the element is already added to the parent, just remove the element
309- el_nodes . splice ( i , 1 )
310- } else {
311- // otherwise, we can just replace it with the component
312- el_nodes [ i ] = MappedOwnerNode
313- AddedToParentElements = true
314- }
315- out . push ( el_node )
316- el_node_data . component = MappedOwnerNode
317- continue els
318- }
319- if ( el_node . children . length ) to_check . push ( el_node . children )
320- }
321- el_nodes = to_check [ index ++ ]
322- }
285+ export function gatherElementMap (
286+ owner : Solid . Owner ,
287+ map : Map < Element , Solid . Component > = new Map ( ) ,
288+ eli : ElementInterface < Element > ,
289+ ) : Map < Element , Solid . Component > {
290+
291+ if ( markOwnerType ( owner ) === NodeType . Component ) {
292+ for ( let el of resolveElements ( owner . value , eli ) ) {
293+ map . set ( el , owner as Solid . Component )
323294 }
324-
325- let el_json : Mapped . Owner = {
326- id : getSdtId ( el , ObjectType . Element ) ,
327- type : NodeType . Element ,
328- name : eli . getName ( el ) ?? UNKNOWN ,
329- children : [ ] ,
330- }
331- out . push ( el_json )
332- ElementsMap . set ( el_json , { el, component : MappedOwnerNode } )
333-
334- mapElements ( eli . getChildren ( el ) , parent_children , eli , el_json . children )
335295 }
336-
337- return out
296+
297+ for ( let child of owner_each_child ( owner ) ) {
298+ gatherElementMap ( child , map , eli )
299+ }
300+
301+ return map
338302}
339303
340304function mapChildren < TEl extends object > (
@@ -360,6 +324,8 @@ function mapChildren<TEl extends object>(
360324 return children
361325}
362326
327+ let element_set = new Set < any > ( )
328+
363329function mapOwner < TEl extends object > (
364330 owner : Solid . Owner ,
365331 parent : Mapped . Owner | null ,
@@ -390,7 +356,7 @@ function mapOwner<TEl extends object>(
390356 The provider component will be omitted
391357 */
392358 if ( name === 'provider' &&
393- owner . owned &&
359+ owner . owned != null &&
394360 owner . owned . length === 1 &&
395361 markOwnerType ( first_owned = owner . owned [ 0 ] ! ) === NodeType . Context
396362 ) {
@@ -404,7 +370,7 @@ function mapOwner<TEl extends object>(
404370 // Refresh
405371 // omitting refresh memo — map it's children instead
406372 let refresh = getComponentRefreshNode ( owner as Solid . Component )
407- if ( refresh ) {
373+ if ( refresh != null ) {
408374 mapped . hmr = true
409375 owner = refresh
410376 }
@@ -417,24 +383,153 @@ function mapOwner<TEl extends object>(
417383 }
418384 }
419385
420- AddedToParentElements = false as boolean
421- MappedOwnerNode = mapped
422-
386+ mapChildren ( owner , mapped , config , mapped . children )
387+
423388 // Map html elements in DOM mode
424389 if ( config . mode === TreeWalkerMode . DOM ) {
425390 // elements might already be resolved when mapping components
426391 resolved_els ??= resolveElements ( owner . value , config . eli )
427- mapElements ( resolved_els , parent ?. children , config . eli , mapped . children )
428- }
429392
430- // global `AddedToParentElements` will be changed in mapChildren
431- let addedToParent = AddedToParentElements
393+ let elements_stack_arr = [ resolved_els ] as ( ElementChildren < TEl > ) [ ]
394+ let elements_stack_idx = [ 0 ]
395+ let elements_stack_owner = [ mapped ]
396+ let elements_stack_len = 1
432397
433- mapChildren ( owner , mapped , config , mapped . children )
398+ let children_stack_arr = [ mapped . children ]
399+ let children_stack_idx = [ 0 ]
400+ let children_stack_len = 1
434401
435- return addedToParent ? undefined : mapped
436- }
402+ while ( children_stack_len > 0 ) {
403+
404+ let children = children_stack_arr [ children_stack_len - 1 ] !
405+ let child_idx = children_stack_idx [ children_stack_len - 1 ] !
406+
407+ if ( child_idx >= children . length ) {
408+ children_stack_len -= 1
409+ continue
410+ }
411+
412+ children_stack_idx [ children_stack_len - 1 ] ! += 1
413+
414+ let child = children [ child_idx ] !
415+
416+ if ( child . type === NodeType . Element ) {
417+
418+ // Don't go over added element children
419+ // TODO: add children cap stack
420+ if ( children_stack_len - 1 === 0 ) {
421+ continue
422+ }
423+
424+ while ( elements_stack_len > 0 ) {
425+
426+ let elements = elements_stack_arr [ elements_stack_len - 1 ] !
427+ let el_idx = elements_stack_idx [ elements_stack_len - 1 ] !
428+ let el_owner = elements_stack_owner [ elements_stack_len - 1 ] !
429+
430+ if ( el_idx >= elements . length ) {
431+ elements_stack_len -= 1
432+ continue
433+ }
434+
435+ elements_stack_idx [ elements_stack_len - 1 ] ! += 1
436+
437+ let el = elements [ el_idx ] !
438+ let el_id = getSdtId ( el , ObjectType . Element )
439+
440+ // Child has this element
441+ if ( el_id === child . id ) {
442+ if ( elements_stack_len > 1 ) {
443+ el_owner . children . push ( children_stack_arr [ 0 ] ! [ children_stack_idx [ 0 ] ! - 1 ] ! )
444+ children_stack_arr [ 0 ] ! . splice ( children_stack_idx [ 0 ] ! - 1 , 1 )
445+ children_stack_idx [ 0 ] ! -= 1
446+ }
447+ children_stack_len = 0
437448
449+ // Skip remaining elements from the child
450+ for ( let skip_child_idx = child_idx + 1 ; ; ) {
451+ let el_idx = elements_stack_idx [ elements_stack_len - 1 ] !
452+
453+ if ( el_idx >= elements . length ||
454+ skip_child_idx >= children . length ||
455+ children [ skip_child_idx ] ! . id !== getSdtId ( elements [ el_idx ] ! , ObjectType . Element )
456+ ) {
457+ break
458+ }
459+
460+ elements_stack_idx [ elements_stack_len - 1 ] ! += 1
461+ skip_child_idx += 1
462+ }
463+
464+ break
465+ }
466+
467+ if ( element_set . has ( el ) ) {
468+ continue
469+ }
470+
471+ else {
472+ let el_json : Mapped . Owner = {
473+ id : el_id ,
474+ type : NodeType . Element ,
475+ name : config . eli . getName ( el ) ?? UNKNOWN ,
476+ children : [ ] ,
477+ }
478+ el_owner . children . push ( el_json )
479+ element_set . add ( el )
480+
481+ elements_stack_arr [ elements_stack_len ] = config . eli . getChildren ( el )
482+ elements_stack_idx [ elements_stack_len ] = 0
483+ elements_stack_owner [ elements_stack_len ] = el_json
484+ elements_stack_len += 1
485+ }
486+ }
487+
488+ } else {
489+ children_stack_arr [ children_stack_len ] = child . children
490+ children_stack_idx [ children_stack_len ] = 0
491+ children_stack_len += 1
492+ continue
493+ }
494+ }
495+
496+ // append remaining elements to children
497+ while ( elements_stack_len > 0 ) {
498+ let elements = elements_stack_arr [ elements_stack_len - 1 ] !
499+ let idx = elements_stack_idx [ elements_stack_len - 1 ] !
500+ let el_owner = elements_stack_owner [ elements_stack_len - 1 ] !
501+
502+ if ( idx >= elements . length ) {
503+ elements_stack_len -= 1
504+ continue
505+ }
506+
507+ elements_stack_idx [ elements_stack_len - 1 ] ! += 1
508+
509+ let el = elements [ idx ] !
510+
511+ if ( element_set . has ( el ) ) {
512+ continue
513+ }
514+
515+ let el_json : Mapped . Owner = {
516+ id : getSdtId ( el , ObjectType . Element ) ,
517+ type : NodeType . Element ,
518+ name : config . eli . getName ( el ) ?? UNKNOWN ,
519+ children : [ ] ,
520+ }
521+ el_owner . children . push ( el_json )
522+ element_set . add ( el )
523+
524+ elements_stack_arr [ elements_stack_len ] = config . eli . getChildren ( el )
525+ elements_stack_idx [ elements_stack_len ] = 0
526+ elements_stack_owner [ elements_stack_len ] = el_json
527+ elements_stack_len += 1
528+ }
529+ }
530+
531+ return mapped
532+ }
438533
439534export const walkSolidTree = /*#__PURE__*/ untrackedCallback ( function < TEl extends object > (
440535 owner : Solid . Owner | Solid . Root ,
@@ -444,12 +539,7 @@ export const walkSolidTree = /*#__PURE__*/ untrackedCallback(function <TEl exten
444539 const r = mapOwner ( owner , null , config ) !
445540
446541 if ( config . mode === TreeWalkerMode . DOM ) {
447- // Register all mapped element nodes to their components
448- for ( let [ elNode , { el, component} ] of ElementsMap ) {
449- registerElement ( config . registry , component . id , elNode . id , el as TEl )
450- }
451-
452- ElementsMap . clear ( )
542+ element_set . clear ( )
453543 }
454544
455545 return r
0 commit comments