333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
 * merge-estraverse-visitors
 *   merge multiple estraverse visitors into one
 * 
 * https://github.com/twada/merge-estraverse-visitors
 *
 * Copyright (c) 2016 Takuto Wada
 * Licensed under the MIT license.
 *   https://twada.mit-license.org/
 */
'use strict';
 
var estraverse = require('estraverse');
 
 
function SubVisitor () {
    this.skipStartNode = null;
    this.broken = false;
}
SubVisitor.prototype.isBroken = function () {
    return !!this.broken;
};
SubVisitor.prototype.markBroken = function () {
    return this.broken = true;
};
SubVisitor.prototype.isSkipping = function (controller) {
    return this.skipStartNode && (this.skipStartNode !== controller.current());
};
SubVisitor.prototype.startSkipping = function (controller) {
    this.skipStartNode = controller.current();
};
SubVisitor.prototype.finishSkippingIfLeavingFrom = function (controller) {
    if (this.skipStartNode === controller.current()) {
        this.skipStartNode = null;
    }
};
 
 
function noop () {
}
 
function createSubVisitors (visitors) {
    var enters = [];
    var leaves = [];
    var subVisitor, i, v, len = visitors.length;
    for(i = 0; i < len; i += 1) {
        v = visitors[i];
        subVisitor = new SubVisitor();
        subVisitor.enter = (typeof v.enter === 'function') ? v.enter : noop;
        subVisitor.leave = (typeof v.leave === 'function') ? v.leave : noop;
        enters.push(subVisitor);
        leaves.unshift(subVisitor);
    }
    return {
        enters: enters,
        leaves: leaves
    };
}
 
 
module.exports = function mergeVisitors (visitors) {
    var subVisitors = createSubVisitors(visitors);
    return {
        enter: function (currentNode, parentNode) {
            var orig = this;
            subVisitors.enters.forEach(function (subVisitor) {
                var controller = Object.create(orig);
                if (subVisitor.isBroken()) {
                    return;
                }
                if (subVisitor.isSkipping(controller)) {
                    return;
                }
                controller.notify = function notify (flag) {
                    switch (flag) {
                    case estraverse.VisitorOption.Skip:
                        subVisitor.startSkipping(controller);
                        return;
                    case estraverse.VisitorOption.Break:
                        subVisitor.markBroken();
                        return;
                    default:
                        orig.notify.call(orig, flag);
                    }
                };
                var ret = subVisitor.enter.call(controller, currentNode, parentNode);
                switch (ret) {
                case estraverse.VisitorOption.Skip:
                    subVisitor.startSkipping(controller);
                    break;
                case estraverse.VisitorOption.Break:
                    subVisitor.markBroken();
                    break;
                }
            });
        },
        leave: function (currentNode, parentNode) {
            var orig = this;
            var replacements = [];
            subVisitors.leaves.forEach(function (subVisitor) {
                var controller = Object.create(orig);
                if (subVisitor.isBroken()) {
                    return;
                }
                if (subVisitor.isSkipping(controller)) {
                    return;
                }
                subVisitor.finishSkippingIfLeavingFrom(controller);
                controller.notify = function notify (flag) {
                    switch (flag) {
                    case estraverse.VisitorOption.Skip:
                        // subVisitor.startSkipping(controller);  // meaningless
                        return;
                    case estraverse.VisitorOption.Break:
                        subVisitor.markBroken();
                        return;
                    default:
                        orig.notify.call(orig, flag);
                    }
                };
                var ret = subVisitor.leave.call(controller, currentNode, parentNode);
                switch (ret) {
                case estraverse.VisitorOption.Skip:
                    // subVisitor.startSkipping(controller);  // meaningless
                    return;
                case estraverse.VisitorOption.Break:
                    subVisitor.markBroken();
                    return;
                }
                if (typeof ret === 'object' && ret !== null && typeof ret.type === 'string') {
                    replacements.push(ret);
                }
            });
            if (replacements.length === 1) {
                return replacements[0];
            }
            return undefined;
        }
    };
};