|
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'
|
8 | 74 |
|
9 | 75 | /**
|
10 | 76 | * Find nodes in `parent` after a `child` or after an index, that pass `test`.
|
11 | 77 | *
|
12 |
| - * @template {Node} Kind |
13 |
| - * Node type. |
14 |
| - * |
15 |
| - * @overload |
16 |
| - * @param {Parent} parent |
17 |
| - * @param {Node | number} index |
18 |
| - * @param {import('unist-util-is').Test} test |
19 |
| - * @returns {Array<Kind>} |
20 |
| - * |
21 |
| - * @overload |
22 |
| - * @param {Parent} parent |
23 |
| - * @param {Node | number} index |
24 |
| - * @param {Test} [test] |
25 |
| - * @returns {Array<Node>} |
26 |
| - * |
27 |
| - * @param {Parent} parent |
| 78 | + * @param parent |
28 | 79 | * Parent node.
|
29 |
| - * @param {Node | number} index |
30 |
| - * Child of `parent` or it’s index. |
31 |
| - * @param {Test} [test] |
32 |
| - * `unist-util-is`-compatible test. |
33 |
| - * @returns {Array<Node>} |
34 |
| - * Children of `parent` that pass `test`. |
| 80 | + * @param index |
| 81 | + * Child node or index. |
| 82 | + * @param [test=undefined] |
| 83 | + * Test for child to look for (optional). |
| 84 | + * @returns |
| 85 | + * Children (matching `test`, if given). |
35 | 86 | */
|
36 |
| -export function findAllAfter(parent, index, test) { |
37 |
| - const is = convert(test) |
38 |
| - /** @type {Array<Node>} */ |
39 |
| - const results = [] |
| 87 | +export const findAllAfter = |
| 88 | + // Note: overloads like this are needed to support optional generics. |
| 89 | + /** |
| 90 | + * @type {( |
| 91 | + * (<Kind extends UnistParent, Check extends Test>(parent: Kind, index: Child<Kind> | number, test: Check) => Array<Matches<Child<Kind>, Check>>) & |
| 92 | + * (<Kind extends UnistParent>(parent: Kind, index: Child<Kind> | number, test?: null | undefined) => Array<Child<Kind>>) |
| 93 | + * )} |
| 94 | + */ |
| 95 | + ( |
| 96 | + /** |
| 97 | + * @param {UnistParent} parent |
| 98 | + * @param {UnistNode | number} index |
| 99 | + * @param {Test} [test=undefined] |
| 100 | + * @returns {Array<UnistNode>} |
| 101 | + */ |
| 102 | + function (parent, index, test) { |
| 103 | + const is = convert(test) |
| 104 | + /** @type {Array<UnistNode>} */ |
| 105 | + const results = [] |
40 | 106 |
|
41 |
| - if (!parent || !parent.type || !parent.children) { |
42 |
| - throw new Error('Expected parent node') |
43 |
| - } |
| 107 | + if (!parent || !parent.type || !parent.children) { |
| 108 | + throw new Error('Expected parent node') |
| 109 | + } |
44 | 110 |
|
45 |
| - if (typeof index === 'number') { |
46 |
| - if (index < 0 || index === Number.POSITIVE_INFINITY) { |
47 |
| - throw new Error('Expected positive finite number as index') |
48 |
| - } |
49 |
| - } else { |
50 |
| - index = parent.children.indexOf(index) |
| 111 | + if (typeof index === 'number') { |
| 112 | + if (index < 0 || index === Number.POSITIVE_INFINITY) { |
| 113 | + throw new Error('Expected positive finite number as index') |
| 114 | + } |
| 115 | + } else { |
| 116 | + index = parent.children.indexOf(index) |
51 | 117 |
|
52 |
| - if (index < 0) { |
53 |
| - throw new Error('Expected child node or index') |
54 |
| - } |
55 |
| - } |
| 118 | + if (index < 0) { |
| 119 | + throw new Error('Expected child node or index') |
| 120 | + } |
| 121 | + } |
56 | 122 |
|
57 |
| - while (++index < parent.children.length) { |
58 |
| - if (is(parent.children[index], index, parent)) { |
59 |
| - results.push(parent.children[index]) |
60 |
| - } |
61 |
| - } |
| 123 | + while (++index < parent.children.length) { |
| 124 | + if (is(parent.children[index], index, parent)) { |
| 125 | + results.push(parent.children[index]) |
| 126 | + } |
| 127 | + } |
62 | 128 |
|
63 |
| - return results |
64 |
| -} |
| 129 | + return results |
| 130 | + } |
| 131 | + ) |
0 commit comments