/** * @typedef {import('unist').Node} UnistNode * @typedef {import('unist').Parent} UnistParent */ /** * @typedef {Exclude | undefined} Test * Test from `unist-util-is`. * * Note: we have remove and add `undefined`, because otherwise when generating * automatic `.d.ts` files, TS tries to flatten paths from a local perspective, * which doesn’t work when publishing on npm. */ /** * @typedef {( * Fn extends (value: any) => value is infer Thing * ? Thing * : Fallback * )} Predicate * Get the value of a type guard `Fn`. * @template Fn * Value; typically function that is a type guard (such as `(x): x is Y`). * @template Fallback * Value to yield if `Fn` is not a type guard. */ /** * @typedef {( * Check extends null | undefined // No test. * ? Value * : Value extends {type: Check} // String (type) test. * ? Value * : Value extends Check // Partial test. * ? Value * : Check extends Function // Function test. * ? Predicate extends Value * ? Predicate * : never * : never // Some other test? * )} MatchesOne * Check whether a node matches a primitive check in the type system. * @template Value * Value; typically unist `Node`. * @template Check * Value; typically `unist-util-is`-compatible test, but not arrays. */ /** * @typedef {( * Check extends Array * ? MatchesOne * : MatchesOne * )} Matches * Check whether a node matches a check in the type system. * @template Value * Value; typically unist `Node`. * @template Check * Value; typically `unist-util-is`-compatible test. */ /** * @typedef {( * Kind extends {children: Array} * ? Child * : never * )} Child * Collect nodes that can be parents of `Child`. * @template {UnistNode} Kind * All node types. */ import {convert} from 'unist-util-is' /** * Find the first node in `parent` after another `node` or after an index, * that passes `test`. * * @param parent * Parent node. * @param index * Child node or index. * @param [test=undefined] * Test for child to look for (optional). * @returns * A child (matching `test`, if given) or `undefined`. */ export const findAfter = // Note: overloads like this are needed to support optional generics. /** * @type {( * ((parent: Kind, index: Child | number, test: Check) => Matches, Check> | undefined) & * ((parent: Kind, index: Child | number, test?: null | undefined) => Child | undefined) * )} */ ( /** * @param {UnistParent} parent * @param {UnistNode | number} index * @param {Test} [test] * @returns {UnistNode | undefined} */ function (parent, index, test) { const is = convert(test) if (!parent || !parent.type || !parent.children) { throw new Error('Expected parent node') } if (typeof index === 'number') { if (index < 0 || index === Number.POSITIVE_INFINITY) { throw new Error('Expected positive finite number as index') } } else { index = parent.children.indexOf(index) if (index < 0) { throw new Error('Expected child node or index') } } while (++index < parent.children.length) { if (is(parent.children[index], index, parent)) { return parent.children[index] } } return undefined } )