11/**
2- * @typedef {import('unist').Node } Node
3- * @typedef {import('unist').Parent } Parent
4- * @typedef {import('unist-util-is').Test } Test
2+ * @typedef {import('unist').Node } UnistNode
3+ * @typedef {import('unist').Parent } UnistParent
4+ */
5+
6+ /**
7+ * @typedef {Exclude<import('unist-util-is').Test, undefined> | undefined } Test
8+ * Test from `unist-util-is`.
9+ *
10+ * Note: we have remove and add `undefined`, because otherwise when generating
11+ * automatic `.d.ts` files, TS tries to flatten paths from a local perspective,
12+ * which doesn’t work when publishing on npm.
13+ */
14+
15+ /**
16+ * @typedef {(
17+ * Fn extends (value: any) => value is infer Thing
18+ * ? Thing
19+ * : Fallback
20+ * )} Predicate
21+ * Get the value of a type guard `Fn`.
22+ * @template Fn
23+ * Value; typically function that is a type guard (such as `(x): x is Y`).
24+ * @template Fallback
25+ * Value to yield if `Fn` is not a type guard.
26+ */
27+
28+ /**
29+ * @typedef {(
30+ * Check extends null | undefined // No test.
31+ * ? Value
32+ * : Value extends {type: Check} // String (type) test.
33+ * ? Value
34+ * : Value extends Check // Partial test.
35+ * ? Value
36+ * : Check extends Function // Function test.
37+ * ? Predicate<Check, Value> extends Value
38+ * ? Predicate<Check, Value>
39+ * : never
40+ * : never // Some other test?
41+ * )} MatchesOne
42+ * Check whether a node matches a primitive check in the type system.
43+ * @template Value
44+ * Value; typically unist `Node`.
45+ * @template Check
46+ * Value; typically `unist-util-is`-compatible test, but not arrays.
47+ */
48+
49+ /**
50+ * @typedef {(
51+ * Check extends Array<any>
52+ * ? MatchesOne<Value, Check[keyof Check]>
53+ * : MatchesOne<Value, Check>
54+ * )} Matches
55+ * Check whether a node matches a check in the type system.
56+ * @template Value
57+ * Value; typically unist `Node`.
58+ * @template Check
59+ * Value; typically `unist-util-is`-compatible test.
60+ */
61+
62+ /**
63+ * @typedef {(
64+ * Kind extends {children: Array<infer Child>}
65+ * ? Child
66+ * : never
67+ * )} Child
68+ * Collect nodes that can be parents of `Child`.
69+ * @template {UnistNode} Kind
70+ * All node types.
571 */
672
773import { convert } from 'unist-util-is'
@@ -10,59 +76,66 @@ import {convert} from 'unist-util-is'
1076 * Find the first node in `parent` before another `node` or before an index,
1177 * that passes `test`.
1278 *
13- * @template {Node} Kind
14- * Node type.
15- *
16- * @overload
17- * @param {Parent } parent
18- * @param {Node | number } index
19- * @param {import('unist-util-is').Test } test
20- * @returns {Kind | undefined }
21- *
22- * @overload
23- * @param {Parent } parent
24- * @param {Node | number } index
25- * @param {Test } [test]
26- * @returns {Node | undefined }
27- *
28- * @param {Parent } parent
79+ * @param parent
2980 * Parent node.
30- * @param { Node | number } index
31- * Child of `parent`, or it’s index.
32- * @param { Test } [test]
33- * `unist-util-is`-compatible test .
34- * @returns { Node | undefined }
35- * Child of `parent` or `undefined`.
81+ * @param index
82+ * Child node or index.
83+ * @param [test=undefined ]
84+ * Test for child to look for (optional) .
85+ * @returns
86+ * A child (matching `test`, if given) or `undefined`.
3687 */
37- export function findBefore ( parent , index , test ) {
38- const is = convert ( test )
88+ export const findBefore =
89+ // Note: overloads like this are needed to support optional generics.
90+ /**
91+ * @type {(
92+ * (<Kind extends UnistParent, Check extends Test>(parent: Kind, index: Child<Kind> | number, test: Check) => Matches<Child<Kind>, Check> | undefined) &
93+ * (<Kind extends UnistParent>(parent: Kind, index: Child<Kind> | number, test?: null | undefined) => Child<Kind> | undefined)
94+ * )}
95+ */
96+ (
97+ /**
98+ * @param {UnistParent } parent
99+ * Parent node.
100+ * @param {UnistNode | number } index
101+ * Child node or index.
102+ * @param {Test } [test=undefined]
103+ * Test for child to look for.
104+ * @returns {UnistNode | undefined }
105+ * A child (matching `test`, if given) or `undefined`.
106+ */
107+ function ( parent , index , test ) {
108+ const is = convert ( test )
39109
40- if ( ! parent || ! parent . type || ! parent . children ) {
41- throw new Error ( 'Expected parent node' )
42- }
110+ if ( ! parent || ! parent . type || ! parent . children ) {
111+ throw new Error ( 'Expected parent node' )
112+ }
43113
44- if ( typeof index === 'number' ) {
45- if ( index < 0 || index === Number . POSITIVE_INFINITY ) {
46- throw new Error ( 'Expected positive finite number as index' )
47- }
48- } else {
49- index = parent . children . indexOf ( index )
114+ if ( typeof index === 'number' ) {
115+ if ( index < 0 || index === Number . POSITIVE_INFINITY ) {
116+ throw new Error ( 'Expected positive finite number as index' )
117+ }
118+ } else {
119+ index = parent . children . indexOf ( index )
50120
51- if ( index < 0 ) {
52- throw new Error ( 'Expected child node or index' )
53- }
54- }
121+ if ( index < 0 ) {
122+ throw new Error ( 'Expected child node or index' )
123+ }
124+ }
55125
56- // Performance.
57- if ( index > parent . children . length ) {
58- index = parent . children . length
59- }
126+ // Performance.
127+ if ( index > parent . children . length ) {
128+ index = parent . children . length
129+ }
60130
61- while ( index -- ) {
62- if ( is ( parent . children [ index ] , index , parent ) ) {
63- return parent . children [ index ]
64- }
65- }
131+ while ( index -- ) {
132+ const child = parent . children [ index ]
133+
134+ if ( is ( child , index , parent ) ) {
135+ return child
136+ }
137+ }
66138
67- return undefined
68- }
139+ return undefined
140+ }
141+ )
0 commit comments