131 lines
3.5 KiB
JavaScript
131 lines
3.5 KiB
JavaScript
|
/**
|
|||
|
* @typedef {import('unist').Node} UnistNode
|
|||
|
* @typedef {import('unist').Parent} UnistParent
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* @typedef {Exclude<import('unist-util-is').Test, undefined> | 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<Check, Value> extends Value
|
|||
|
* ? Predicate<Check, Value>
|
|||
|
* : 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<any>
|
|||
|
* ? MatchesOne<Value, Check[keyof Check]>
|
|||
|
* : MatchesOne<Value, Check>
|
|||
|
* )} 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<infer Child>}
|
|||
|
* ? 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 {(
|
|||
|
* (<Kind extends UnistParent, Check extends Test>(parent: Kind, index: Child<Kind> | number, test: Check) => Matches<Child<Kind>, Check> | undefined) &
|
|||
|
* (<Kind extends UnistParent>(parent: Kind, index: Child<Kind> | number, test?: null | undefined) => Child<Kind> | 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
|
|||
|
}
|
|||
|
)
|