1 | /**
|
2 | * @author Titus Wormer
|
3 | * @copyright 2015 Titus Wormer. All rights reserved.
|
4 | * @module unist:util:visit
|
5 | * @fileoverview Utility to recursively walk over unist nodes.
|
6 | */
|
7 |
|
8 | ;
|
9 |
|
10 | /**
|
11 | * Walk forwards.
|
12 | *
|
13 | * @param {Array.<*>} values - Things to iterate over,
|
14 | * forwards.
|
15 | * @param {function(*, number): boolean} callback - Function
|
16 | * to invoke.
|
17 | * @return {boolean} - False if iteration stopped.
|
18 | */
|
19 | function forwards(values, callback) {
|
20 | var index = -1;
|
21 | var length = values.length;
|
22 |
|
23 | while (++index < length) {
|
24 | if (callback(values[index], index) === false) {
|
25 | return false;
|
26 | }
|
27 | }
|
28 |
|
29 | return true;
|
30 | }
|
31 |
|
32 | /**
|
33 | * Walk backwards.
|
34 | *
|
35 | * @param {Array.<*>} values - Things to iterate over,
|
36 | * backwards.
|
37 | * @param {function(*, number): boolean} callback - Function
|
38 | * to invoke.
|
39 | * @return {boolean} - False if iteration stopped.
|
40 | */
|
41 | function backwards(values, callback) {
|
42 | var index = values.length;
|
43 | var length = -1;
|
44 |
|
45 | while (--index > length) {
|
46 | if (callback(values[index], index) === false) {
|
47 | return false;
|
48 | }
|
49 | }
|
50 |
|
51 | return true;
|
52 | }
|
53 |
|
54 | /**
|
55 | * Visit.
|
56 | *
|
57 | * @param {Node} tree - Root node
|
58 | * @param {string} [type] - Node type.
|
59 | * @param {function(node): boolean?} callback - Invoked
|
60 | * with each found node. Can return `false` to stop.
|
61 | * @param {boolean} [reverse] - By default, `visit` will
|
62 | * walk forwards, when `reverse` is `true`, `visit`
|
63 | * walks backwards.
|
64 | */
|
65 | function visit(tree, type, callback, reverse) {
|
66 | var iterate;
|
67 | var one;
|
68 | var all;
|
69 |
|
70 | if (typeof type === 'function') {
|
71 | reverse = callback;
|
72 | callback = type;
|
73 | type = null;
|
74 | }
|
75 |
|
76 | iterate = reverse ? backwards : forwards;
|
77 |
|
78 | /**
|
79 | * Visit `children` in `parent`.
|
80 | */
|
81 | all = function (children, parent) {
|
82 | return iterate(children, function (child, index) {
|
83 | return child && one(child, index, parent);
|
84 | });
|
85 | };
|
86 |
|
87 | /**
|
88 | * Visit a single node.
|
89 | */
|
90 | one = function (node, index, parent) {
|
91 | var result;
|
92 |
|
93 | index = index || (parent ? 0 : null);
|
94 |
|
95 | if (!type || node.type === type) {
|
96 | result = callback(node, index, parent || null);
|
97 | }
|
98 |
|
99 | if (node.children && result !== false) {
|
100 | return all(node.children, node);
|
101 | }
|
102 |
|
103 | return result;
|
104 | };
|
105 |
|
106 | one(tree);
|
107 | }
|
108 |
|
109 | /*
|
110 | * Expose.
|
111 | */
|
112 |
|
113 | module.exports = visit;
|