1
1
/**
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.
5
71
*/
6
72
7
73
import { convert } from 'unist-util-is'
@@ -10,62 +76,63 @@ import {convert} from 'unist-util-is'
10
76
* Find the nodes in `parent` before another `node` or before an index, that
11
77
* pass `test`.
12
78
*
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 {Array<Kind> }
21
- *
22
- * @overload
23
- * @param {Parent } parent
24
- * @param {Node | number } index
25
- * @param {Test } [test]
26
- * @returns {Array<Node> }
27
- *
28
- * @param {Parent } parent
79
+ * @param parent
29
80
* 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 { Array<Node> }
35
- * Children of `parent` that pass `test` .
81
+ * @param index
82
+ * Child node or index.
83
+ * @param [test=undefined ]
84
+ * Test for child to look for (optional) .
85
+ * @returns
86
+ * Children (matching `test`, if given) .
36
87
*/
37
- export function findAllBefore ( parent , index , test ) {
38
- const is = convert ( test )
39
- /** @type {Array<Node> } */
40
- const results = [ ]
41
- let offset = - 1
88
+ export const findAllBefore =
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) => Array<Matches<Child<Kind>, Check>>) &
93
+ * (<Kind extends UnistParent>(parent: Kind, index: Child<Kind> | number, test?: null | undefined) => Array<Child<Kind>>)
94
+ * )}
95
+ */
96
+ (
97
+ /**
98
+ * @param {UnistParent } parent
99
+ * @param {UnistNode | number } index
100
+ * @param {Test } [test]
101
+ * @returns {Array<UnistNode> }
102
+ */
103
+ function ( parent , index , test ) {
104
+ const is = convert ( test )
105
+ /** @type {Array<UnistNode> } */
106
+ const results = [ ]
107
+ let offset = - 1
42
108
43
- if ( ! parent || ! parent . type || ! parent . children ) {
44
- throw new Error ( 'Expected parent node' )
45
- }
109
+ if ( ! parent || ! parent . type || ! parent . children ) {
110
+ throw new Error ( 'Expected parent node' )
111
+ }
46
112
47
- if ( typeof index === 'number' ) {
48
- if ( index < 0 || index === Number . POSITIVE_INFINITY ) {
49
- throw new Error ( 'Expected positive finite number as index' )
50
- }
51
- } else {
52
- index = parent . children . indexOf ( index )
113
+ if ( typeof index === 'number' ) {
114
+ if ( index < 0 || index === Number . POSITIVE_INFINITY ) {
115
+ throw new Error ( 'Expected positive finite number as index' )
116
+ }
117
+ } else {
118
+ index = parent . children . indexOf ( index )
53
119
54
- if ( index < 0 ) {
55
- throw new Error ( 'Expected child node or index' )
56
- }
57
- }
120
+ if ( index < 0 ) {
121
+ throw new Error ( 'Expected child node or index' )
122
+ }
123
+ }
58
124
59
- // Performance.
60
- if ( index > parent . children . length ) {
61
- index = parent . children . length
62
- }
125
+ // Performance.
126
+ if ( index > parent . children . length ) {
127
+ index = parent . children . length
128
+ }
63
129
64
- while ( ++ offset < index ) {
65
- if ( is ( parent . children [ offset ] , offset , parent ) ) {
66
- results . push ( parent . children [ offset ] )
67
- }
68
- }
130
+ while ( ++ offset < index ) {
131
+ if ( is ( parent . children [ offset ] , offset , parent ) ) {
132
+ results . push ( parent . children [ offset ] )
133
+ }
134
+ }
69
135
70
- return results
71
- }
136
+ return results
137
+ }
138
+ )
0 commit comments