/* eslint-disable @typescript-eslint/ban-types */ import type {Node, Parent} from 'unist' import type {Test} from 'unist-util-is' /** * Union of the action types */ export type Action = boolean | 'skip' /** * Move to the sibling at index next (after node itself is completely * traversed). * Useful if mutating the tree, such as removing the node the visitor is * currently on, or any of its previous siblings (or next siblings, in case of * reverse) Results less than 0 or greater than or equal to `children.length` * stop traversing the parent. */ export type Index = number /** * List with one or two values, the first an action, the second an index. */ export type ActionTuple = [ (Action | null | undefined | void)?, (Index | null | undefined)? ] /** * Any value that can be returned from a visitor */ export type VisitorResult = | null | undefined | Action | Index | ActionTuple | void /** * Internal utility to collect all descendants of in `Tree`. */ export type InclusiveDescendant< Tree extends Node = never, Found = void > = Tree extends Parent ? | Tree | InclusiveDescendant< Exclude, Found | Tree > : Tree type Predicate = Fn extends ( value: any ) => value is infer Thing ? Thing : Fallback type MatchesOne = // Is this a node? Value extends Node ? // No test. Check extends null ? Value : // No test. Check extends undefined ? Value : // Function test. Check extends Function ? Extract> : // String (type) test. Value['type'] extends Check ? Value : // Partial test. Value extends Check ? Value : never : never export type Matches = // Is this a list? Check extends any[] ? MatchesOne : MatchesOne /** * Invoked when a node (matching test, if given) is found. * Visitors are free to transform node. * They can also transform the parent of node (the last of ancestors). * Replacing node itself, if `SKIP` is not returned, still causes its descendants to be visited. * If adding or removing previous siblings (or next siblings, in case of reverse) of node, * visitor should return a new index (number) to specify the sibling to traverse after node is traversed. * Adding or removing next siblings of node (or previous siblings, in case of reverse) * is handled as expected without needing to return a new index. * Removing the children property of an ancestor still results in them being traversed. */ export type Visitor< Visited extends Node = Node, Ancestor extends Parent = Parent > = (node: Visited, ancestors: Ancestor[]) => VisitorResult export type BuildVisitor< Tree extends Node = Node, Check extends Test = string > = Visitor< Matches, Check>, Extract, Parent> > /* eslint-enable @typescript-eslint/ban-types */