source: trip-planner-front/node_modules/estraverse/estraverse.js@ 6c1585f

Last change on this file since 6c1585f was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 25.6 KB
Line 
1/*
2 Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
3 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
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 ClassBody: 'ClassBody',
88 ClassDeclaration: 'ClassDeclaration',
89 ClassExpression: 'ClassExpression',
90 ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7.
91 ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7.
92 ConditionalExpression: 'ConditionalExpression',
93 ContinueStatement: 'ContinueStatement',
94 DebuggerStatement: 'DebuggerStatement',
95 DirectiveStatement: 'DirectiveStatement',
96 DoWhileStatement: 'DoWhileStatement',
97 EmptyStatement: 'EmptyStatement',
98 ExportAllDeclaration: 'ExportAllDeclaration',
99 ExportDefaultDeclaration: 'ExportDefaultDeclaration',
100 ExportNamedDeclaration: 'ExportNamedDeclaration',
101 ExportSpecifier: 'ExportSpecifier',
102 ExpressionStatement: 'ExpressionStatement',
103 ForStatement: 'ForStatement',
104 ForInStatement: 'ForInStatement',
105 ForOfStatement: 'ForOfStatement',
106 FunctionDeclaration: 'FunctionDeclaration',
107 FunctionExpression: 'FunctionExpression',
108 GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7.
109 Identifier: 'Identifier',
110 IfStatement: 'IfStatement',
111 ImportExpression: 'ImportExpression',
112 ImportDeclaration: 'ImportDeclaration',
113 ImportDefaultSpecifier: 'ImportDefaultSpecifier',
114 ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
115 ImportSpecifier: 'ImportSpecifier',
116 Literal: 'Literal',
117 LabeledStatement: 'LabeledStatement',
118 LogicalExpression: 'LogicalExpression',
119 MemberExpression: 'MemberExpression',
120 MetaProperty: 'MetaProperty',
121 MethodDefinition: 'MethodDefinition',
122 ModuleSpecifier: 'ModuleSpecifier',
123 NewExpression: 'NewExpression',
124 ObjectExpression: 'ObjectExpression',
125 ObjectPattern: 'ObjectPattern',
126 Program: 'Program',
127 Property: 'Property',
128 RestElement: 'RestElement',
129 ReturnStatement: 'ReturnStatement',
130 SequenceExpression: 'SequenceExpression',
131 SpreadElement: 'SpreadElement',
132 Super: 'Super',
133 SwitchStatement: 'SwitchStatement',
134 SwitchCase: 'SwitchCase',
135 TaggedTemplateExpression: 'TaggedTemplateExpression',
136 TemplateElement: 'TemplateElement',
137 TemplateLiteral: 'TemplateLiteral',
138 ThisExpression: 'ThisExpression',
139 ThrowStatement: 'ThrowStatement',
140 TryStatement: 'TryStatement',
141 UnaryExpression: 'UnaryExpression',
142 UpdateExpression: 'UpdateExpression',
143 VariableDeclaration: 'VariableDeclaration',
144 VariableDeclarator: 'VariableDeclarator',
145 WhileStatement: 'WhileStatement',
146 WithStatement: 'WithStatement',
147 YieldExpression: 'YieldExpression'
148 };
149
150 VisitorKeys = {
151 AssignmentExpression: ['left', 'right'],
152 AssignmentPattern: ['left', 'right'],
153 ArrayExpression: ['elements'],
154 ArrayPattern: ['elements'],
155 ArrowFunctionExpression: ['params', 'body'],
156 AwaitExpression: ['argument'], // CAUTION: It's deferred to ES7.
157 BlockStatement: ['body'],
158 BinaryExpression: ['left', 'right'],
159 BreakStatement: ['label'],
160 CallExpression: ['callee', 'arguments'],
161 CatchClause: ['param', 'body'],
162 ClassBody: ['body'],
163 ClassDeclaration: ['id', 'superClass', 'body'],
164 ClassExpression: ['id', 'superClass', 'body'],
165 ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7.
166 ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7.
167 ConditionalExpression: ['test', 'consequent', 'alternate'],
168 ContinueStatement: ['label'],
169 DebuggerStatement: [],
170 DirectiveStatement: [],
171 DoWhileStatement: ['body', 'test'],
172 EmptyStatement: [],
173 ExportAllDeclaration: ['source'],
174 ExportDefaultDeclaration: ['declaration'],
175 ExportNamedDeclaration: ['declaration', 'specifiers', 'source'],
176 ExportSpecifier: ['exported', 'local'],
177 ExpressionStatement: ['expression'],
178 ForStatement: ['init', 'test', 'update', 'body'],
179 ForInStatement: ['left', 'right', 'body'],
180 ForOfStatement: ['left', 'right', 'body'],
181 FunctionDeclaration: ['id', 'params', 'body'],
182 FunctionExpression: ['id', 'params', 'body'],
183 GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7.
184 Identifier: [],
185 IfStatement: ['test', 'consequent', 'alternate'],
186 ImportExpression: ['source'],
187 ImportDeclaration: ['specifiers', 'source'],
188 ImportDefaultSpecifier: ['local'],
189 ImportNamespaceSpecifier: ['local'],
190 ImportSpecifier: ['imported', 'local'],
191 Literal: [],
192 LabeledStatement: ['label', 'body'],
193 LogicalExpression: ['left', 'right'],
194 MemberExpression: ['object', 'property'],
195 MetaProperty: ['meta', 'property'],
196 MethodDefinition: ['key', 'value'],
197 ModuleSpecifier: [],
198 NewExpression: ['callee', 'arguments'],
199 ObjectExpression: ['properties'],
200 ObjectPattern: ['properties'],
201 Program: ['body'],
202 Property: ['key', 'value'],
203 RestElement: [ 'argument' ],
204 ReturnStatement: ['argument'],
205 SequenceExpression: ['expressions'],
206 SpreadElement: ['argument'],
207 Super: [],
208 SwitchStatement: ['discriminant', 'cases'],
209 SwitchCase: ['test', 'consequent'],
210 TaggedTemplateExpression: ['tag', 'quasi'],
211 TemplateElement: [],
212 TemplateLiteral: ['quasis', 'expressions'],
213 ThisExpression: [],
214 ThrowStatement: ['argument'],
215 TryStatement: ['block', 'handler', 'finalizer'],
216 UnaryExpression: ['argument'],
217 UpdateExpression: ['argument'],
218 VariableDeclaration: ['declarations'],
219 VariableDeclarator: ['id', 'init'],
220 WhileStatement: ['test', 'body'],
221 WithStatement: ['object', 'body'],
222 YieldExpression: ['argument']
223 };
224
225 // unique id
226 BREAK = {};
227 SKIP = {};
228 REMOVE = {};
229
230 VisitorOption = {
231 Break: BREAK,
232 Skip: SKIP,
233 Remove: REMOVE
234 };
235
236 function Reference(parent, key) {
237 this.parent = parent;
238 this.key = key;
239 }
240
241 Reference.prototype.replace = function replace(node) {
242 this.parent[this.key] = node;
243 };
244
245 Reference.prototype.remove = function remove() {
246 if (Array.isArray(this.parent)) {
247 this.parent.splice(this.key, 1);
248 return true;
249 } else {
250 this.replace(null);
251 return false;
252 }
253 };
254
255 function Element(node, path, wrap, ref) {
256 this.node = node;
257 this.path = path;
258 this.wrap = wrap;
259 this.ref = ref;
260 }
261
262 function Controller() { }
263
264 // API:
265 // return property path array from root to current node
266 Controller.prototype.path = function path() {
267 var i, iz, j, jz, result, element;
268
269 function addToPath(result, path) {
270 if (Array.isArray(path)) {
271 for (j = 0, jz = path.length; j < jz; ++j) {
272 result.push(path[j]);
273 }
274 } else {
275 result.push(path);
276 }
277 }
278
279 // root node
280 if (!this.__current.path) {
281 return null;
282 }
283
284 // first node is sentinel, second node is root element
285 result = [];
286 for (i = 2, iz = this.__leavelist.length; i < iz; ++i) {
287 element = this.__leavelist[i];
288 addToPath(result, element.path);
289 }
290 addToPath(result, this.__current.path);
291 return result;
292 };
293
294 // API:
295 // return type of current node
296 Controller.prototype.type = function () {
297 var node = this.current();
298 return node.type || this.__current.wrap;
299 };
300
301 // API:
302 // return array of parent elements
303 Controller.prototype.parents = function parents() {
304 var i, iz, result;
305
306 // first node is sentinel
307 result = [];
308 for (i = 1, iz = this.__leavelist.length; i < iz; ++i) {
309 result.push(this.__leavelist[i].node);
310 }
311
312 return result;
313 };
314
315 // API:
316 // return current node
317 Controller.prototype.current = function current() {
318 return this.__current.node;
319 };
320
321 Controller.prototype.__execute = function __execute(callback, element) {
322 var previous, result;
323
324 result = undefined;
325
326 previous = this.__current;
327 this.__current = element;
328 this.__state = null;
329 if (callback) {
330 result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node);
331 }
332 this.__current = previous;
333
334 return result;
335 };
336
337 // API:
338 // notify control skip / break
339 Controller.prototype.notify = function notify(flag) {
340 this.__state = flag;
341 };
342
343 // API:
344 // skip child nodes of current node
345 Controller.prototype.skip = function () {
346 this.notify(SKIP);
347 };
348
349 // API:
350 // break traversals
351 Controller.prototype['break'] = function () {
352 this.notify(BREAK);
353 };
354
355 // API:
356 // remove node
357 Controller.prototype.remove = function () {
358 this.notify(REMOVE);
359 };
360
361 Controller.prototype.__initialize = function(root, visitor) {
362 this.visitor = visitor;
363 this.root = root;
364 this.__worklist = [];
365 this.__leavelist = [];
366 this.__current = null;
367 this.__state = null;
368 this.__fallback = null;
369 if (visitor.fallback === 'iteration') {
370 this.__fallback = Object.keys;
371 } else if (typeof visitor.fallback === 'function') {
372 this.__fallback = visitor.fallback;
373 }
374
375 this.__keys = VisitorKeys;
376 if (visitor.keys) {
377 this.__keys = Object.assign(Object.create(this.__keys), visitor.keys);
378 }
379 };
380
381 function isNode(node) {
382 if (node == null) {
383 return false;
384 }
385 return typeof node === 'object' && typeof node.type === 'string';
386 }
387
388 function isProperty(nodeType, key) {
389 return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key;
390 }
391
392 Controller.prototype.traverse = function traverse(root, visitor) {
393 var worklist,
394 leavelist,
395 element,
396 node,
397 nodeType,
398 ret,
399 key,
400 current,
401 current2,
402 candidates,
403 candidate,
404 sentinel;
405
406 this.__initialize(root, visitor);
407
408 sentinel = {};
409
410 // reference
411 worklist = this.__worklist;
412 leavelist = this.__leavelist;
413
414 // initialize
415 worklist.push(new Element(root, null, null, null));
416 leavelist.push(new Element(null, null, null, null));
417
418 while (worklist.length) {
419 element = worklist.pop();
420
421 if (element === sentinel) {
422 element = leavelist.pop();
423
424 ret = this.__execute(visitor.leave, element);
425
426 if (this.__state === BREAK || ret === BREAK) {
427 return;
428 }
429 continue;
430 }
431
432 if (element.node) {
433
434 ret = this.__execute(visitor.enter, element);
435
436 if (this.__state === BREAK || ret === BREAK) {
437 return;
438 }
439
440 worklist.push(sentinel);
441 leavelist.push(element);
442
443 if (this.__state === SKIP || ret === SKIP) {
444 continue;
445 }
446
447 node = element.node;
448 nodeType = node.type || element.wrap;
449 candidates = this.__keys[nodeType];
450 if (!candidates) {
451 if (this.__fallback) {
452 candidates = this.__fallback(node);
453 } else {
454 throw new Error('Unknown node type ' + nodeType + '.');
455 }
456 }
457
458 current = candidates.length;
459 while ((current -= 1) >= 0) {
460 key = candidates[current];
461 candidate = node[key];
462 if (!candidate) {
463 continue;
464 }
465
466 if (Array.isArray(candidate)) {
467 current2 = candidate.length;
468 while ((current2 -= 1) >= 0) {
469 if (!candidate[current2]) {
470 continue;
471 }
472 if (isProperty(nodeType, candidates[current])) {
473 element = new Element(candidate[current2], [key, current2], 'Property', null);
474 } else if (isNode(candidate[current2])) {
475 element = new Element(candidate[current2], [key, current2], null, null);
476 } else {
477 continue;
478 }
479 worklist.push(element);
480 }
481 } else if (isNode(candidate)) {
482 worklist.push(new Element(candidate, key, null, null));
483 }
484 }
485 }
486 }
487 };
488
489 Controller.prototype.replace = function replace(root, visitor) {
490 var worklist,
491 leavelist,
492 node,
493 nodeType,
494 target,
495 element,
496 current,
497 current2,
498 candidates,
499 candidate,
500 sentinel,
501 outer,
502 key;
503
504 function removeElem(element) {
505 var i,
506 key,
507 nextElem,
508 parent;
509
510 if (element.ref.remove()) {
511 // When the reference is an element of an array.
512 key = element.ref.key;
513 parent = element.ref.parent;
514
515 // If removed from array, then decrease following items' keys.
516 i = worklist.length;
517 while (i--) {
518 nextElem = worklist[i];
519 if (nextElem.ref && nextElem.ref.parent === parent) {
520 if (nextElem.ref.key < key) {
521 break;
522 }
523 --nextElem.ref.key;
524 }
525 }
526 }
527 }
528
529 this.__initialize(root, visitor);
530
531 sentinel = {};
532
533 // reference
534 worklist = this.__worklist;
535 leavelist = this.__leavelist;
536
537 // initialize
538 outer = {
539 root: root
540 };
541 element = new Element(root, null, null, new Reference(outer, 'root'));
542 worklist.push(element);
543 leavelist.push(element);
544
545 while (worklist.length) {
546 element = worklist.pop();
547
548 if (element === sentinel) {
549 element = leavelist.pop();
550
551 target = this.__execute(visitor.leave, element);
552
553 // node may be replaced with null,
554 // so distinguish between undefined and null in this place
555 if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) {
556 // replace
557 element.ref.replace(target);
558 }
559
560 if (this.__state === REMOVE || target === REMOVE) {
561 removeElem(element);
562 }
563
564 if (this.__state === BREAK || target === BREAK) {
565 return outer.root;
566 }
567 continue;
568 }
569
570 target = this.__execute(visitor.enter, element);
571
572 // node may be replaced with null,
573 // so distinguish between undefined and null in this place
574 if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) {
575 // replace
576 element.ref.replace(target);
577 element.node = target;
578 }
579
580 if (this.__state === REMOVE || target === REMOVE) {
581 removeElem(element);
582 element.node = null;
583 }
584
585 if (this.__state === BREAK || target === BREAK) {
586 return outer.root;
587 }
588
589 // node may be null
590 node = element.node;
591 if (!node) {
592 continue;
593 }
594
595 worklist.push(sentinel);
596 leavelist.push(element);
597
598 if (this.__state === SKIP || target === SKIP) {
599 continue;
600 }
601
602 nodeType = node.type || element.wrap;
603 candidates = this.__keys[nodeType];
604 if (!candidates) {
605 if (this.__fallback) {
606 candidates = this.__fallback(node);
607 } else {
608 throw new Error('Unknown node type ' + nodeType + '.');
609 }
610 }
611
612 current = candidates.length;
613 while ((current -= 1) >= 0) {
614 key = candidates[current];
615 candidate = node[key];
616 if (!candidate) {
617 continue;
618 }
619
620 if (Array.isArray(candidate)) {
621 current2 = candidate.length;
622 while ((current2 -= 1) >= 0) {
623 if (!candidate[current2]) {
624 continue;
625 }
626 if (isProperty(nodeType, candidates[current])) {
627 element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2));
628 } else if (isNode(candidate[current2])) {
629 element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2));
630 } else {
631 continue;
632 }
633 worklist.push(element);
634 }
635 } else if (isNode(candidate)) {
636 worklist.push(new Element(candidate, key, null, new Reference(node, key)));
637 }
638 }
639 }
640
641 return outer.root;
642 };
643
644 function traverse(root, visitor) {
645 var controller = new Controller();
646 return controller.traverse(root, visitor);
647 }
648
649 function replace(root, visitor) {
650 var controller = new Controller();
651 return controller.replace(root, visitor);
652 }
653
654 function extendCommentRange(comment, tokens) {
655 var target;
656
657 target = upperBound(tokens, function search(token) {
658 return token.range[0] > comment.range[0];
659 });
660
661 comment.extendedRange = [comment.range[0], comment.range[1]];
662
663 if (target !== tokens.length) {
664 comment.extendedRange[1] = tokens[target].range[0];
665 }
666
667 target -= 1;
668 if (target >= 0) {
669 comment.extendedRange[0] = tokens[target].range[1];
670 }
671
672 return comment;
673 }
674
675 function attachComments(tree, providedComments, tokens) {
676 // At first, we should calculate extended comment ranges.
677 var comments = [], comment, len, i, cursor;
678
679 if (!tree.range) {
680 throw new Error('attachComments needs range information');
681 }
682
683 // tokens array is empty, we attach comments to tree as 'leadingComments'
684 if (!tokens.length) {
685 if (providedComments.length) {
686 for (i = 0, len = providedComments.length; i < len; i += 1) {
687 comment = deepCopy(providedComments[i]);
688 comment.extendedRange = [0, tree.range[0]];
689 comments.push(comment);
690 }
691 tree.leadingComments = comments;
692 }
693 return tree;
694 }
695
696 for (i = 0, len = providedComments.length; i < len; i += 1) {
697 comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
698 }
699
700 // This is based on John Freeman's implementation.
701 cursor = 0;
702 traverse(tree, {
703 enter: function (node) {
704 var comment;
705
706 while (cursor < comments.length) {
707 comment = comments[cursor];
708 if (comment.extendedRange[1] > node.range[0]) {
709 break;
710 }
711
712 if (comment.extendedRange[1] === node.range[0]) {
713 if (!node.leadingComments) {
714 node.leadingComments = [];
715 }
716 node.leadingComments.push(comment);
717 comments.splice(cursor, 1);
718 } else {
719 cursor += 1;
720 }
721 }
722
723 // already out of owned node
724 if (cursor === comments.length) {
725 return VisitorOption.Break;
726 }
727
728 if (comments[cursor].extendedRange[0] > node.range[1]) {
729 return VisitorOption.Skip;
730 }
731 }
732 });
733
734 cursor = 0;
735 traverse(tree, {
736 leave: function (node) {
737 var comment;
738
739 while (cursor < comments.length) {
740 comment = comments[cursor];
741 if (node.range[1] < comment.extendedRange[0]) {
742 break;
743 }
744
745 if (node.range[1] === comment.extendedRange[0]) {
746 if (!node.trailingComments) {
747 node.trailingComments = [];
748 }
749 node.trailingComments.push(comment);
750 comments.splice(cursor, 1);
751 } else {
752 cursor += 1;
753 }
754 }
755
756 // already out of owned node
757 if (cursor === comments.length) {
758 return VisitorOption.Break;
759 }
760
761 if (comments[cursor].extendedRange[0] > node.range[1]) {
762 return VisitorOption.Skip;
763 }
764 }
765 });
766
767 return tree;
768 }
769
770 exports.version = require('./package.json').version;
771 exports.Syntax = Syntax;
772 exports.traverse = traverse;
773 exports.replace = replace;
774 exports.attachComments = attachComments;
775 exports.VisitorKeys = VisitorKeys;
776 exports.VisitorOption = VisitorOption;
777 exports.Controller = Controller;
778 exports.cloneEnvironment = function () { return clone({}); };
779
780 return exports;
781}(exports));
782/* vim: set sw=4 ts=4 et tw=80 : */
Note: See TracBrowser for help on using the repository browser.