Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/@javascript-obfuscator/estraverse/estraverse.js
1126 views
1
/*
2
Copyright (C) 2012-2013 Yusuke Suzuki <[email protected]>
3
Copyright (C) 2012 Ariya Hidayat <[email protected]>
4
5
Redistribution and use in source and binary forms, with or without
6
modification, are permitted provided that the following conditions are met:
7
8
* Redistributions of source code must retain the above copyright
9
notice, this list of conditions and the following disclaimer.
10
* Redistributions in binary form must reproduce the above copyright
11
notice, this list of conditions and the following disclaimer in the
12
documentation and/or other materials provided with the distribution.
13
14
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
18
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
*/
25
/*jslint vars:false, bitwise:true*/
26
/*jshint indent:4*/
27
/*global exports:true*/
28
(function clone(exports) {
29
'use strict';
30
31
var Syntax,
32
VisitorOption,
33
VisitorKeys,
34
BREAK,
35
SKIP,
36
REMOVE;
37
38
function deepCopy(obj) {
39
var ret = {}, key, val;
40
for (key in obj) {
41
if (obj.hasOwnProperty(key)) {
42
val = obj[key];
43
if (typeof val === 'object' && val !== null) {
44
ret[key] = deepCopy(val);
45
} else {
46
ret[key] = val;
47
}
48
}
49
}
50
return ret;
51
}
52
53
// based on LLVM libc++ upper_bound / lower_bound
54
// MIT License
55
56
function upperBound(array, func) {
57
var diff, len, i, current;
58
59
len = array.length;
60
i = 0;
61
62
while (len) {
63
diff = len >>> 1;
64
current = i + diff;
65
if (func(array[current])) {
66
len = diff;
67
} else {
68
i = current + 1;
69
len -= diff + 1;
70
}
71
}
72
return i;
73
}
74
75
Syntax = {
76
AssignmentExpression: 'AssignmentExpression',
77
AssignmentPattern: 'AssignmentPattern',
78
ArrayExpression: 'ArrayExpression',
79
ArrayPattern: 'ArrayPattern',
80
ArrowFunctionExpression: 'ArrowFunctionExpression',
81
AwaitExpression: 'AwaitExpression', // CAUTION: It's deferred to ES7.
82
BlockStatement: 'BlockStatement',
83
BinaryExpression: 'BinaryExpression',
84
BreakStatement: 'BreakStatement',
85
CallExpression: 'CallExpression',
86
CatchClause: 'CatchClause',
87
ChainExpression: 'ChainExpression',
88
ClassBody: 'ClassBody',
89
ClassDeclaration: 'ClassDeclaration',
90
ClassExpression: 'ClassExpression',
91
ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7.
92
ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7.
93
ConditionalExpression: 'ConditionalExpression',
94
ContinueStatement: 'ContinueStatement',
95
DebuggerStatement: 'DebuggerStatement',
96
DirectiveStatement: 'DirectiveStatement',
97
DoWhileStatement: 'DoWhileStatement',
98
EmptyStatement: 'EmptyStatement',
99
ExportAllDeclaration: 'ExportAllDeclaration',
100
ExportDefaultDeclaration: 'ExportDefaultDeclaration',
101
ExportNamedDeclaration: 'ExportNamedDeclaration',
102
ExportSpecifier: 'ExportSpecifier',
103
ExpressionStatement: 'ExpressionStatement',
104
ForStatement: 'ForStatement',
105
ForInStatement: 'ForInStatement',
106
ForOfStatement: 'ForOfStatement',
107
FunctionDeclaration: 'FunctionDeclaration',
108
FunctionExpression: 'FunctionExpression',
109
GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7.
110
Identifier: 'Identifier',
111
IfStatement: 'IfStatement',
112
ImportExpression: 'ImportExpression',
113
ImportDeclaration: 'ImportDeclaration',
114
ImportDefaultSpecifier: 'ImportDefaultSpecifier',
115
ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
116
ImportSpecifier: 'ImportSpecifier',
117
Literal: 'Literal',
118
LabeledStatement: 'LabeledStatement',
119
LogicalExpression: 'LogicalExpression',
120
MemberExpression: 'MemberExpression',
121
MetaProperty: 'MetaProperty',
122
MethodDefinition: 'MethodDefinition',
123
ModuleSpecifier: 'ModuleSpecifier',
124
NewExpression: 'NewExpression',
125
ObjectExpression: 'ObjectExpression',
126
ObjectPattern: 'ObjectPattern',
127
PrivateIdentifier: 'PrivateIdentifier',
128
Program: 'Program',
129
Property: 'Property',
130
PropertyDefinition: 'PropertyDefinition',
131
RestElement: 'RestElement',
132
ReturnStatement: 'ReturnStatement',
133
SequenceExpression: 'SequenceExpression',
134
SpreadElement: 'SpreadElement',
135
StaticBlock: 'StaticBlock',
136
Super: 'Super',
137
SwitchStatement: 'SwitchStatement',
138
SwitchCase: 'SwitchCase',
139
TaggedTemplateExpression: 'TaggedTemplateExpression',
140
TemplateElement: 'TemplateElement',
141
TemplateLiteral: 'TemplateLiteral',
142
ThisExpression: 'ThisExpression',
143
ThrowStatement: 'ThrowStatement',
144
TryStatement: 'TryStatement',
145
UnaryExpression: 'UnaryExpression',
146
UpdateExpression: 'UpdateExpression',
147
VariableDeclaration: 'VariableDeclaration',
148
VariableDeclarator: 'VariableDeclarator',
149
WhileStatement: 'WhileStatement',
150
WithStatement: 'WithStatement',
151
YieldExpression: 'YieldExpression'
152
};
153
154
VisitorKeys = {
155
AssignmentExpression: ['left', 'right'],
156
AssignmentPattern: ['left', 'right'],
157
ArrayExpression: ['elements'],
158
ArrayPattern: ['elements'],
159
ArrowFunctionExpression: ['params', 'body'],
160
AwaitExpression: ['argument'], // CAUTION: It's deferred to ES7.
161
BlockStatement: ['body'],
162
BinaryExpression: ['left', 'right'],
163
BreakStatement: ['label'],
164
CallExpression: ['callee', 'arguments'],
165
CatchClause: ['param', 'body'],
166
ChainExpression: ['expression'],
167
ClassBody: ['body'],
168
ClassDeclaration: ['id', 'superClass', 'body'],
169
ClassExpression: ['id', 'superClass', 'body'],
170
ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7.
171
ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7.
172
ConditionalExpression: ['test', 'consequent', 'alternate'],
173
ContinueStatement: ['label'],
174
DebuggerStatement: [],
175
DirectiveStatement: [],
176
DoWhileStatement: ['body', 'test'],
177
EmptyStatement: [],
178
ExportAllDeclaration: ['source'],
179
ExportDefaultDeclaration: ['declaration'],
180
ExportNamedDeclaration: ['declaration', 'specifiers', 'source'],
181
ExportSpecifier: ['exported', 'local'],
182
ExpressionStatement: ['expression'],
183
ForStatement: ['init', 'test', 'update', 'body'],
184
ForInStatement: ['left', 'right', 'body'],
185
ForOfStatement: ['left', 'right', 'body'],
186
FunctionDeclaration: ['id', 'params', 'body'],
187
FunctionExpression: ['id', 'params', 'body'],
188
GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7.
189
Identifier: [],
190
IfStatement: ['test', 'consequent', 'alternate'],
191
ImportExpression: ['source'],
192
ImportDeclaration: ['specifiers', 'source'],
193
ImportDefaultSpecifier: ['local'],
194
ImportNamespaceSpecifier: ['local'],
195
ImportSpecifier: ['imported', 'local'],
196
Literal: [],
197
LabeledStatement: ['label', 'body'],
198
LogicalExpression: ['left', 'right'],
199
MemberExpression: ['object', 'property'],
200
MetaProperty: ['meta', 'property'],
201
MethodDefinition: ['key', 'value'],
202
ModuleSpecifier: [],
203
NewExpression: ['callee', 'arguments'],
204
ObjectExpression: ['properties'],
205
ObjectPattern: ['properties'],
206
PrivateIdentifier: [],
207
Program: ['body'],
208
Property: ['key', 'value'],
209
PropertyDefinition: ['key', 'value'],
210
RestElement: [ 'argument' ],
211
ReturnStatement: ['argument'],
212
SequenceExpression: ['expressions'],
213
SpreadElement: ['argument'],
214
StaticBlock: ['body'],
215
Super: [],
216
SwitchStatement: ['discriminant', 'cases'],
217
SwitchCase: ['test', 'consequent'],
218
TaggedTemplateExpression: ['tag', 'quasi'],
219
TemplateElement: [],
220
TemplateLiteral: ['quasis', 'expressions'],
221
ThisExpression: [],
222
ThrowStatement: ['argument'],
223
TryStatement: ['block', 'handler', 'finalizer'],
224
UnaryExpression: ['argument'],
225
UpdateExpression: ['argument'],
226
VariableDeclaration: ['declarations'],
227
VariableDeclarator: ['id', 'init'],
228
WhileStatement: ['test', 'body'],
229
WithStatement: ['object', 'body'],
230
YieldExpression: ['argument']
231
};
232
233
// unique id
234
BREAK = {};
235
SKIP = {};
236
REMOVE = {};
237
238
VisitorOption = {
239
Break: BREAK,
240
Skip: SKIP,
241
Remove: REMOVE
242
};
243
244
function Reference(parent, key) {
245
this.parent = parent;
246
this.key = key;
247
}
248
249
Reference.prototype.replace = function replace(node) {
250
this.parent[this.key] = node;
251
};
252
253
Reference.prototype.remove = function remove() {
254
if (Array.isArray(this.parent)) {
255
this.parent.splice(this.key, 1);
256
return true;
257
} else {
258
this.replace(null);
259
return false;
260
}
261
};
262
263
function Element(node, path, wrap, ref) {
264
this.node = node;
265
this.path = path;
266
this.wrap = wrap;
267
this.ref = ref;
268
}
269
270
function Controller() { }
271
272
// API:
273
// return property path array from root to current node
274
Controller.prototype.path = function path() {
275
var i, iz, j, jz, result, element;
276
277
function addToPath(result, path) {
278
if (Array.isArray(path)) {
279
for (j = 0, jz = path.length; j < jz; ++j) {
280
result.push(path[j]);
281
}
282
} else {
283
result.push(path);
284
}
285
}
286
287
// root node
288
if (!this.__current.path) {
289
return null;
290
}
291
292
// first node is sentinel, second node is root element
293
result = [];
294
for (i = 2, iz = this.__leavelist.length; i < iz; ++i) {
295
element = this.__leavelist[i];
296
addToPath(result, element.path);
297
}
298
addToPath(result, this.__current.path);
299
return result;
300
};
301
302
// API:
303
// return type of current node
304
Controller.prototype.type = function () {
305
var node = this.current();
306
return node.type || this.__current.wrap;
307
};
308
309
// API:
310
// return array of parent elements
311
Controller.prototype.parents = function parents() {
312
var i, iz, result;
313
314
// first node is sentinel
315
result = [];
316
for (i = 1, iz = this.__leavelist.length; i < iz; ++i) {
317
result.push(this.__leavelist[i].node);
318
}
319
320
return result;
321
};
322
323
// API:
324
// return current node
325
Controller.prototype.current = function current() {
326
return this.__current.node;
327
};
328
329
Controller.prototype.__execute = function __execute(callback, element) {
330
var previous, result;
331
332
result = undefined;
333
334
previous = this.__current;
335
this.__current = element;
336
this.__state = null;
337
if (callback) {
338
result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node);
339
}
340
this.__current = previous;
341
342
return result;
343
};
344
345
// API:
346
// notify control skip / break
347
Controller.prototype.notify = function notify(flag) {
348
this.__state = flag;
349
};
350
351
// API:
352
// skip child nodes of current node
353
Controller.prototype.skip = function () {
354
this.notify(SKIP);
355
};
356
357
// API:
358
// break traversals
359
Controller.prototype['break'] = function () {
360
this.notify(BREAK);
361
};
362
363
// API:
364
// remove node
365
Controller.prototype.remove = function () {
366
this.notify(REMOVE);
367
};
368
369
Controller.prototype.__initialize = function(root, visitor) {
370
this.visitor = visitor;
371
this.root = root;
372
this.__worklist = [];
373
this.__leavelist = [];
374
this.__current = null;
375
this.__state = null;
376
this.__fallback = null;
377
if (visitor.fallback === 'iteration') {
378
this.__fallback = Object.keys;
379
} else if (typeof visitor.fallback === 'function') {
380
this.__fallback = visitor.fallback;
381
}
382
383
this.__keys = VisitorKeys;
384
if (visitor.keys) {
385
this.__keys = Object.assign(Object.create(this.__keys), visitor.keys);
386
}
387
};
388
389
function isNode(node) {
390
if (node == null) {
391
return false;
392
}
393
return typeof node === 'object' && typeof node.type === 'string';
394
}
395
396
function isProperty(nodeType, key) {
397
return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key;
398
}
399
400
function candidateExistsInLeaveList(leavelist, candidate) {
401
for (var i = leavelist.length - 1; i >= 0; --i) {
402
if (leavelist[i].node === candidate) {
403
return true;
404
}
405
}
406
return false;
407
}
408
409
Controller.prototype.traverse = function traverse(root, visitor) {
410
var worklist,
411
leavelist,
412
element,
413
node,
414
nodeType,
415
ret,
416
key,
417
current,
418
current2,
419
candidates,
420
candidate,
421
sentinel;
422
423
this.__initialize(root, visitor);
424
425
sentinel = {};
426
427
// reference
428
worklist = this.__worklist;
429
leavelist = this.__leavelist;
430
431
// initialize
432
worklist.push(new Element(root, null, null, null));
433
leavelist.push(new Element(null, null, null, null));
434
435
while (worklist.length) {
436
element = worklist.pop();
437
438
if (element === sentinel) {
439
element = leavelist.pop();
440
441
ret = this.__execute(visitor.leave, element);
442
443
if (this.__state === BREAK || ret === BREAK) {
444
return;
445
}
446
continue;
447
}
448
449
if (element.node) {
450
451
ret = this.__execute(visitor.enter, element);
452
453
if (this.__state === BREAK || ret === BREAK) {
454
return;
455
}
456
457
worklist.push(sentinel);
458
leavelist.push(element);
459
460
if (this.__state === SKIP || ret === SKIP) {
461
continue;
462
}
463
464
node = element.node;
465
nodeType = node.type || element.wrap;
466
candidates = this.__keys[nodeType];
467
if (!candidates) {
468
if (this.__fallback) {
469
candidates = this.__fallback(node);
470
} else {
471
throw new Error('Unknown node type ' + nodeType + '.');
472
}
473
}
474
475
current = candidates.length;
476
while ((current -= 1) >= 0) {
477
key = candidates[current];
478
candidate = node[key];
479
if (!candidate) {
480
continue;
481
}
482
483
if (Array.isArray(candidate)) {
484
current2 = candidate.length;
485
while ((current2 -= 1) >= 0) {
486
if (!candidate[current2]) {
487
continue;
488
}
489
490
if (candidateExistsInLeaveList(leavelist, candidate[current2])) {
491
continue;
492
}
493
494
if (isProperty(nodeType, candidates[current])) {
495
element = new Element(candidate[current2], [key, current2], 'Property', null);
496
} else if (isNode(candidate[current2])) {
497
element = new Element(candidate[current2], [key, current2], null, null);
498
} else {
499
continue;
500
}
501
worklist.push(element);
502
}
503
} else if (isNode(candidate)) {
504
if (candidateExistsInLeaveList(leavelist, candidate)) {
505
continue;
506
}
507
508
worklist.push(new Element(candidate, key, null, null));
509
}
510
}
511
}
512
}
513
};
514
515
Controller.prototype.replace = function replace(root, visitor) {
516
var worklist,
517
leavelist,
518
node,
519
nodeType,
520
target,
521
element,
522
current,
523
current2,
524
candidates,
525
candidate,
526
sentinel,
527
outer,
528
key;
529
530
function removeElem(element) {
531
var i,
532
key,
533
nextElem,
534
parent;
535
536
if (element.ref.remove()) {
537
// When the reference is an element of an array.
538
key = element.ref.key;
539
parent = element.ref.parent;
540
541
// If removed from array, then decrease following items' keys.
542
i = worklist.length;
543
while (i--) {
544
nextElem = worklist[i];
545
if (nextElem.ref && nextElem.ref.parent === parent) {
546
if (nextElem.ref.key < key) {
547
break;
548
}
549
--nextElem.ref.key;
550
}
551
}
552
}
553
}
554
555
this.__initialize(root, visitor);
556
557
sentinel = {};
558
559
// reference
560
worklist = this.__worklist;
561
leavelist = this.__leavelist;
562
563
// initialize
564
outer = {
565
root: root
566
};
567
element = new Element(root, null, null, new Reference(outer, 'root'));
568
worklist.push(element);
569
leavelist.push(element);
570
571
while (worklist.length) {
572
element = worklist.pop();
573
574
if (element === sentinel) {
575
element = leavelist.pop();
576
577
target = this.__execute(visitor.leave, element);
578
579
// node may be replaced with null,
580
// so distinguish between undefined and null in this place
581
if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) {
582
// replace
583
element.ref.replace(target);
584
}
585
586
if (this.__state === REMOVE || target === REMOVE) {
587
removeElem(element);
588
}
589
590
if (this.__state === BREAK || target === BREAK) {
591
return outer.root;
592
}
593
continue;
594
}
595
596
target = this.__execute(visitor.enter, element);
597
598
// node may be replaced with null,
599
// so distinguish between undefined and null in this place
600
if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) {
601
// replace
602
element.ref.replace(target);
603
element.node = target;
604
}
605
606
if (this.__state === REMOVE || target === REMOVE) {
607
removeElem(element);
608
element.node = null;
609
}
610
611
if (this.__state === BREAK || target === BREAK) {
612
return outer.root;
613
}
614
615
// node may be null
616
node = element.node;
617
if (!node) {
618
continue;
619
}
620
621
worklist.push(sentinel);
622
leavelist.push(element);
623
624
if (this.__state === SKIP || target === SKIP) {
625
continue;
626
}
627
628
nodeType = node.type || element.wrap;
629
candidates = this.__keys[nodeType];
630
if (!candidates) {
631
if (this.__fallback) {
632
candidates = this.__fallback(node);
633
} else {
634
throw new Error('Unknown node type ' + nodeType + '.');
635
}
636
}
637
638
current = candidates.length;
639
while ((current -= 1) >= 0) {
640
key = candidates[current];
641
candidate = node[key];
642
if (!candidate) {
643
continue;
644
}
645
646
if (Array.isArray(candidate)) {
647
current2 = candidate.length;
648
while ((current2 -= 1) >= 0) {
649
if (!candidate[current2]) {
650
continue;
651
}
652
if (isProperty(nodeType, candidates[current])) {
653
element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2));
654
} else if (isNode(candidate[current2])) {
655
element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2));
656
} else {
657
continue;
658
}
659
worklist.push(element);
660
}
661
} else if (isNode(candidate)) {
662
worklist.push(new Element(candidate, key, null, new Reference(node, key)));
663
}
664
}
665
}
666
667
return outer.root;
668
};
669
670
function traverse(root, visitor) {
671
var controller = new Controller();
672
return controller.traverse(root, visitor);
673
}
674
675
function replace(root, visitor) {
676
var controller = new Controller();
677
return controller.replace(root, visitor);
678
}
679
680
function extendCommentRange(comment, tokens) {
681
var target;
682
683
target = upperBound(tokens, function search(token) {
684
return token.range[0] > comment.range[0];
685
});
686
687
comment.extendedRange = [comment.range[0], comment.range[1]];
688
689
if (target !== tokens.length) {
690
comment.extendedRange[1] = tokens[target].range[0];
691
}
692
693
target -= 1;
694
if (target >= 0) {
695
comment.extendedRange[0] = tokens[target].range[1];
696
}
697
698
return comment;
699
}
700
701
function attachComments(tree, providedComments, tokens) {
702
// At first, we should calculate extended comment ranges.
703
var comments = [], comment, len, i, cursor;
704
705
if (!tree.range) {
706
throw new Error('attachComments needs range information');
707
}
708
709
// tokens array is empty, we attach comments to tree as 'leadingComments'
710
if (!tokens.length) {
711
if (providedComments.length) {
712
for (i = 0, len = providedComments.length; i < len; i += 1) {
713
comment = deepCopy(providedComments[i]);
714
comment.extendedRange = [0, tree.range[0]];
715
comments.push(comment);
716
}
717
tree.leadingComments = comments;
718
}
719
return tree;
720
}
721
722
for (i = 0, len = providedComments.length; i < len; i += 1) {
723
comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
724
}
725
726
// This is based on John Freeman's implementation.
727
cursor = 0;
728
traverse(tree, {
729
enter: function (node) {
730
var comment;
731
732
while (cursor < comments.length) {
733
comment = comments[cursor];
734
if (comment.extendedRange[1] > node.range[0]) {
735
break;
736
}
737
738
if (comment.extendedRange[1] === node.range[0]) {
739
if (!node.leadingComments) {
740
node.leadingComments = [];
741
}
742
node.leadingComments.push(comment);
743
comments.splice(cursor, 1);
744
} else {
745
cursor += 1;
746
}
747
}
748
749
// already out of owned node
750
if (cursor === comments.length) {
751
return VisitorOption.Break;
752
}
753
754
if (comments[cursor].extendedRange[0] > node.range[1]) {
755
return VisitorOption.Skip;
756
}
757
}
758
});
759
760
cursor = 0;
761
traverse(tree, {
762
leave: function (node) {
763
var comment;
764
765
while (cursor < comments.length) {
766
comment = comments[cursor];
767
if (node.range[1] < comment.extendedRange[0]) {
768
break;
769
}
770
771
if (node.range[1] === comment.extendedRange[0]) {
772
if (!node.trailingComments) {
773
node.trailingComments = [];
774
}
775
node.trailingComments.push(comment);
776
comments.splice(cursor, 1);
777
} else {
778
cursor += 1;
779
}
780
}
781
782
// already out of owned node
783
if (cursor === comments.length) {
784
return VisitorOption.Break;
785
}
786
787
if (comments[cursor].extendedRange[0] > node.range[1]) {
788
return VisitorOption.Skip;
789
}
790
}
791
});
792
793
return tree;
794
}
795
796
exports.Syntax = Syntax;
797
exports.traverse = traverse;
798
exports.replace = replace;
799
exports.attachComments = attachComments;
800
exports.VisitorKeys = VisitorKeys;
801
exports.VisitorOption = VisitorOption;
802
exports.Controller = Controller;
803
exports.cloneEnvironment = function () { return clone({}); };
804
805
return exports;
806
}(exports));
807
/* vim: set sw=4 ts=4 et tw=80 : */
808
809