import * as assert from "@esfx/internal-assert" ; import { HashMap } from '@esfx/collections-hashmap' ; import { HashSet } from '@esfx/collections-hashset' ; import { Equaler } from '@esfx/equatable' ; import { T } from '@esfx/fn' ; import { Hierarchical , HierarchyIterable , HierarchyProvider , OrderedHierarchyIterable } from "@esfx/iter-hierarchy" ; import { OrderedIterable } from '@esfx/iter-ordered' ; import { Axis } from '@esfx/iter-hierarchy/axis' ; import { toArray } from './scalars' ; function isHierarchyElement < T > ( provider , value ) { return value !== undefined && ( provider . owns === undefined || provider . owns ( value ) ) ; } function createHierarchyIterable ( tag , axis ) { return { [ tag ] : class < TNode > implements HierarchyIterable < TNode > { private _source : HierarchyIterable < TNode > ; private _predicate : ( element : TNode ) => boolean ; private _axis : ( provider : HierarchyProvider < TNode > , element : TNode ) => Iterable < TNode > ; constructor ( source , predicate ) { this . _source = source ; this . _predicate = predicate ; this . _axis = axis ; } * [ Symbol . iterator ] ( ) { const source = this . _source ; const hierarchy = source [ Hierarchical . hierarchy ] ( ) ; const predicate = this . _predicate ; const axis = this . _axis ; for ( const element of source ) { if ( isHierarchyElement ( hierarchy , element ) ) { for ( const related of axis ( hierarchy , element ) ) { if ( predicate ( related ) ) { yield related ; } } } } } [ Hierarchical . hierarchy ] ( ) { return this . _source [ Hierarchical . hierarchy ] ( ) ; } } } [ tag ] ; } const RootHierarchyIterable = createHierarchyIterable ( "RootHierarchyIterable" , Axis . root ) ; category export function root < TNode , U extends TNode > ( source , predicate ) ; export function root < TNode > ( source , predicate ? ) ; export function root < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new RootHierarchyIterable ( source , predicate ) ; } const AncestorsHierarchyIterable = createHierarchyIterable ( "AncestorsHierarchyIterable" , Axis . ancestors ) ; category export function ancestors < TNode , U extends TNode > ( source , predicate ) ; export function ancestors < TNode > ( source , predicate ? ) ; export function ancestors < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new AncestorsHierarchyIterable ( source , predicate ) ; } const AncestorsAndSelfHierarchyIterable = createHierarchyIterable ( "AncestorsAndSelfHierarchyIterable" , Axis . ancestorsAndSelf ) ; category export function ancestorsAndSelf < TNode , U extends TNode > ( source , predicate ) ; export function ancestorsAndSelf < TNode > ( source , predicate ? ) ; export function ancestorsAndSelf < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new AncestorsAndSelfHierarchyIterable ( source , predicate ) ; } const DescendantsHierarchyIterable = createHierarchyIterable ( "DescendantsHierarchyIterable" , Axis . descendants ) ; category export function descendants < TNode , U extends TNode > ( source , predicate ) ; export function descendants < TNode > ( source , predicate ? ) ; export function descendants < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new DescendantsHierarchyIterable ( source , predicate ) ; } const DescendantsAndSelfHierarchyIterable = createHierarchyIterable ( "DescendantsAndSelfHierarchyIterable" , Axis . descendantsAndSelf ) ; category export function descendantsAndSelf < TNode , U extends TNode > ( source , predicate ) ; export function descendantsAndSelf < TNode > ( source , predicate ? ) ; export function descendantsAndSelf < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new DescendantsAndSelfHierarchyIterable ( source , predicate ) ; } const ParentsHierarchyIterable = createHierarchyIterable ( "ParentsHierarchyIterable" , Axis . parents ) ; category export function parents < TNode , U extends TNode > ( source , predicate ) ; export function parents < TNode > ( source , predicate ? ) ; export function parents < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new ParentsHierarchyIterable ( source , predicate ) ; } const SelfHierarchyIterable = createHierarchyIterable ( "SelfHierarchyIterable" , Axis . self ) ; category export function self < TNode , T extends TNode , U extends T > ( source , predicate ) ; export function self < TNode , T extends TNode > ( source , predicate ? ) ; export function self < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new SelfHierarchyIterable ( source , predicate ) ; } const SiblingsHierarchyIterable = createHierarchyIterable ( "SiblingsHierarchyIterable" , Axis . siblings ) ; category export function siblings < TNode , U extends TNode > ( source , predicate ) ; export function siblings < TNode > ( source , predicate ? ) ; export function siblings < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new SiblingsHierarchyIterable ( source , predicate ) ; } const SiblingsAndSelfHierarchyIterable = createHierarchyIterable ( "SiblingsAndSelfHierarchyIterable" , Axis . siblingsAndSelf ) ; category export function siblingsAndSelf < TNode , U extends TNode > ( source , predicate ) ; export function siblingsAndSelf < TNode > ( source , predicate ? ) ; export function siblingsAndSelf < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new SiblingsAndSelfHierarchyIterable ( source , predicate ) ; } const PrecedingSiblingsHierarchyIterable = createHierarchyIterable ( "PrecedingSiblingsHierarchyIterable" , Axis . precedingSiblings ) ; category export function precedingSiblings < TNode , U extends TNode > ( source , predicate ) ; export function precedingSiblings < TNode > ( source , predicate ? ) ; export function precedingSiblings < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new PrecedingSiblingsHierarchyIterable ( source , predicate ) ; } export { precedingSiblings as siblingsBeforeSelf } ; export { followingSiblings as siblingsAfterSelf } ; const FollowingSiblingsHierarchyIterable = createHierarchyIterable ( "FollowingSiblingsHierarchyIterable" , Axis . followingSiblings ) ; category export function followingSiblings < TNode , U extends TNode > ( source , predicate ) ; export function followingSiblings < TNode > ( source , predicate ? ) ; export function followingSiblings < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new FollowingSiblingsHierarchyIterable ( source , predicate ) ; } const PrecedingHierarchyIterable = createHierarchyIterable ( "PrecedingHierarchyIterable" , Axis . preceding ) ; category export function preceding < TNode , U extends TNode > ( source , predicate ) ; export function preceding < TNode > ( source , predicate ? ) ; export function preceding < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new PrecedingHierarchyIterable ( source , predicate ) ; } const FollowingHierarchyIterable = createHierarchyIterable ( "FollowingHierarchyIterable" , Axis . following ) ; category export function following < TNode , U extends TNode > ( source , predicate ) ; export function following < TNode > ( source , predicate ? ) ; export function following < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new FollowingHierarchyIterable ( source , predicate ) ; } const ChildrenHierarchyIterable = createHierarchyIterable ( "ChildrenHierarchyIterable" , Axis . children ) ; category export function children < TNode , U extends TNode > ( source , predicate ) ; export function children < TNode > ( source , predicate ? ) ; export function children < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new ChildrenHierarchyIterable ( source , predicate ) ; } const FirstChildHierarchyIterable = createHierarchyIterable ( "FirstChildHierarchyIterable" , Axis . firstChild ) ; category export function firstChild < TNode , U extends TNode > ( source , predicate ) ; export function firstChild < TNode > ( source , predicate ? ) ; export function firstChild < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new FirstChildHierarchyIterable ( source , predicate ) ; } const LastChildHierarchyIterable = createHierarchyIterable ( "LastChildHierarchyIterable" , Axis . lastChild ) ; category export function lastChild < TNode , U extends TNode > ( source , predicate ) ; export function lastChild < TNode > ( source , predicate ? ) ; export function lastChild < TNode > ( source , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new LastChildHierarchyIterable ( source , predicate ) ; } class NthChildHierarchyIterable < TNode > implements Iterable < TNode > { private _source : HierarchyIterable < TNode > ; private _predicate : ( element : TNode ) => boolean ; private _offset : number ; constructor ( source , offset , predicate ) { this . _source = source ; this . _offset = offset ; this . _predicate = predicate ; } * [ Symbol . iterator ] ( ) { const source = this . _source ; const provider = source [ Hierarchical . hierarchy ] ( ) ; const offset = this . _offset ; const predicate = this . _predicate ; for ( const element of source ) { if ( isHierarchyElement ( provider , element ) ) { for ( const child of Axis . nthChild ( provider , element , offset ) ) { if ( predicate ( child ) ) { yield child ; } } } } } [ Hierarchical . hierarchy ] ( ) { return this . _source [ Hierarchical . hierarchy ] ( ) ; } } param source param offset param predicate category export function nthChild < TNode , U extends TNode > ( source , offset , predicate ) ; export function nthChild < TNode > ( source , offset , predicate ? ) ; export function nthChild < TNode > ( source , offset , predicate = T ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeInteger ( offset , "offset" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; return new NthChildHierarchyIterable ( source , offset , T ) ; } class TopMostIterable < TNode , T extends TNode > implements HierarchyIterable < TNode , T > { private _source : HierarchyIterable < TNode , T > ; private _predicate : ( value : T ) => boolean ; private _equaler : Equaler < TNode > | undefined ; constructor ( source , predicate , equaler ) { this . _source = source ; this . _predicate = predicate ; this . _equaler = equaler ; } * [ Symbol . iterator ] ( ) { const source = this . _source ; const predicate = this . _predicate ; const equaler = this . _equaler ; const hierarchy = source [ Hierarchical . hierarchy ] ( ) ; const topMostNodes = toArray ( source ) ; const ancestors = new HashMap < TNode , HashSet < TNode > > ( equaler ) ; for ( let i = topMostNodes . length - 1 ; i >= 1 ; i -- ) { const node = topMostNodes [ i ] ; for ( let j = i - 1 ; j >= 0 ; j -- ) { const other = topMostNodes [ j ] ; let ancestorsOfNode = ancestors . get ( node ) ; if ( ! ancestorsOfNode ) { ancestorsOfNode = new HashSet ( Axis . ancestors ( hierarchy , node ) , equaler ) ; ancestors . set ( node , ancestorsOfNode ) ; } if ( ancestorsOfNode . has ( other ) ) { topMostNodes . splice ( i , 1 ) ; break ; } let ancestorsOfOther = ancestors . get ( other ) ; if ( ! ancestorsOfOther ) { ancestorsOfOther = new HashSet ( Axis . ancestors ( hierarchy , other ) , equaler ) ; ancestors . set ( other , ancestorsOfOther ) ; } if ( ancestorsOfOther . has ( node ) ) { topMostNodes . splice ( j , 1 ) ; i -- ; } } } for ( const node of topMostNodes ) { if ( predicate ( node ) ) yield node ; } } [ Hierarchical . hierarchy ] ( ) { return this . _source [ Hierarchical . hierarchy ] ( ) ; } } param source param predicate param equaler category export function topMost < TNode , T extends TNode , U extends T > ( source , predicate , equaler ? ) ; param source param predicate param equaler category export function topMost < TNode , T extends TNode > ( source , predicate ? , equaler ? ) ; export function topMost < TNode , T extends TNode > ( source , predicate = T , equaler = Equaler . defaultEqualer ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; assert . mustBeType ( Equaler . hasInstance , equaler , "equaler" ) ; return new TopMostIterable < TNode , T > ( source , predicate , equaler ) ; } class BottomMostIterable < TNode , T extends TNode > implements HierarchyIterable < TNode , T > { private _source : HierarchyIterable < TNode , T > ; private _predicate : ( value : T ) => boolean ; private _equaler : Equaler < TNode > | undefined ; constructor ( source , predicate , equaler ) { this . _source = source ; this . _predicate = predicate ; this . _equaler = equaler ; } * [ Symbol . iterator ] ( ) { const source = this . _source ; const predicate = this . _predicate ; const equaler = this . _equaler ; const hierarchy = source [ Hierarchical . hierarchy ] ( ) ; const bottomMostNodes = toArray ( source ) ; const ancestors = new HashMap < TNode , HashSet < TNode > > ( equaler ) ; for ( let i = bottomMostNodes . length - 1 ; i >= 1 ; i -- ) { const node = bottomMostNodes [ i ] ; for ( let j = i - 1 ; j >= 0 ; j -- ) { const other = bottomMostNodes [ j ] ; let ancestorsOfOther = ancestors . get ( other ) ; if ( ! ancestorsOfOther ) { ancestorsOfOther = new HashSet ( Axis . ancestors ( hierarchy , other ) , equaler ) ; ancestors . set ( other , ancestorsOfOther ) ; } if ( ancestorsOfOther . has ( node ) ) { bottomMostNodes . splice ( i , 1 ) ; break ; } let ancestorsOfNode = ancestors . get ( node ) ; if ( ! ancestorsOfNode ) { ancestorsOfNode = new HashSet ( Axis . ancestors ( hierarchy , node ) , equaler ) ; ancestors . set ( node , ancestorsOfNode ) ; } if ( ancestorsOfNode . has ( other ) ) { bottomMostNodes . splice ( j , 1 ) ; i -- ; } } } for ( const node of bottomMostNodes ) { if ( predicate ( node ) ) yield node ; } } [ Hierarchical . hierarchy ] ( ) { return this . _source [ Hierarchical . hierarchy ] ( ) ; } } param source param predicate category export function bottomMost < TNode , T extends TNode , U extends T > ( source , predicate , equaler ? ) ; param source param predicate param equaler category export function bottomMost < TNode , T extends TNode > ( source , predicate ? , equaler ? ) ; export function bottomMost < TNode , T extends TNode > ( source , predicate = T , equaler = Equaler . defaultEqualer ) { assert . mustBeType ( HierarchyIterable . hasInstance , source , "source" ) ; assert . mustBeFunction ( predicate , "predicate" ) ; assert . mustBeType ( Equaler . hasInstance , equaler , "equaler" ) ; return new BottomMostIterable < TNode , T > ( source , predicate , equaler ) ; } param source param hierarchy param equaler category export function toHierarchy < TNode , T extends TNode = TNode > ( iterable , provider ) ; export function toHierarchy < TNode , T extends TNode = TNode > ( iterable , provider ) ; export function toHierarchy < TNode , T extends TNode = TNode > ( iterable , provider ) { return HierarchyIterable . create ( iterable , provider ) ; }