import { Node } from "@siteimprove/alfa-dom" ; import { Predicate } from "@siteimprove/alfa-predicate" ; import { Sequence } from "@siteimprove/alfa-sequence" ; import { lowestCommonAncestor } from "./lowest-common-ancestor" ; const { equals , or } = Predicate ; const treeOptions = { flattened : true , nested : true } ; /**
 * Get content between two nodes. The relative order of the nodes is unknown.
 * Options let it choose whether the first or second node (in tree order)
 * should be included. By default, exclude both.
 *
 * When the first node is not included, all its subtree is skipped, that is we
 * start looking after the closing tag, not after the opening one.
 *
 * Returns empty sequence in the corner case where both nodes are the same and
 * at least one is excluded (i.e. considers that [X,X[ and ]X,X] are empty).
 *
 * Complexity: the size of the subtree anchored at the lowest common ancestor.
 */ export function getNodesBetween ( node1 , node2 , includeOptions = { includeFirst : false , includeSecond : false } ) { let between = getNodesInclusivelyBetween ( node1 , node2 ) ; if ( between . isEmpty ( ) ) { return between ; } if ( ! includeOptions . includeFirst ) { const first = between . first ( ) . get ( ) ; between = first . closest ( ( ancestor ) => ancestor . next ( treeOptions ) . isSome ( ) ) . flatMap ( ( node ) => node . next ( treeOptions ) ) . map ( ( next ) => between . skipUntil ( ( node ) => node . equals ( next ) ) ) . getOrElse ( Sequence . empty ) ; } between = includeOptions . includeSecond || between . isEmpty ( ) ? between : between . skipLast ( 1 ) ; return between ; } /**
 * Get all nodes between node1 and node2, included.
 */ function getNodesInclusivelyBetween ( node1 , node2 ) { const isFrontier = or ( equals ( node1 ) , equals ( node2 ) ) ; return lowestCommonAncestor ( node1 , node2 , treeOptions ) . map ( ( context ) => context . inclusiveDescendants ( treeOptions ) . skipUntil ( isFrontier ) . skipLastUntil ( isFrontier ) ) . getOrElse ( Sequence . empty ) ; } type Options = { includeFirst : boolean ; includeSecond : boolean ; } ;