UNPKG

5.9 kBJavaScriptView Raw
1/* @flow */
2
3/**
4 * Based on the comment attachment algorithm used in espree and estraverse.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27"use strict";
28
29var _interopRequireDefault = require("babel-runtime/helpers/interop-require-default")["default"];
30
31var _index = require("./index");
32
33var _index2 = _interopRequireDefault(_index);
34
35function last(stack) {
36 return stack[stack.length - 1];
37}
38
39var pp = _index2["default"].prototype;
40
41pp.addComment = function (comment) {
42 this.state.trailingComments.push(comment);
43 this.state.leadingComments.push(comment);
44};
45
46pp.processComment = function (node) {
47 if (node.type === "Program" && node.body.length > 0) return;
48
49 var stack = this.state.commentStack;
50
51 var lastChild = undefined,
52 trailingComments = undefined,
53 i = undefined;
54
55 if (this.state.trailingComments.length > 0) {
56 // If the first comment in trailingComments comes after the
57 // current node, then we're good - all comments in the array will
58 // come after the node and so it's safe to add them as official
59 // trailingComments.
60 if (this.state.trailingComments[0].start >= node.end) {
61 trailingComments = this.state.trailingComments;
62 this.state.trailingComments = [];
63 } else {
64 // Otherwise, if the first comment doesn't come after the
65 // current node, that means we have a mix of leading and trailing
66 // comments in the array and that leadingComments contains the
67 // same items as trailingComments. Reset trailingComments to
68 // zero items and we'll handle this by evaluating leadingComments
69 // later.
70 this.state.trailingComments.length = 0;
71 }
72 } else {
73 var lastInStack = last(stack);
74 if (stack.length > 0 && lastInStack.trailingComments && lastInStack.trailingComments[0].start >= node.end) {
75 trailingComments = lastInStack.trailingComments;
76 lastInStack.trailingComments = null;
77 }
78 }
79
80 // Eating the stack.
81 while (stack.length > 0 && last(stack).start >= node.start) {
82 lastChild = stack.pop();
83 }
84
85 if (lastChild) {
86 if (lastChild.leadingComments) {
87 if (lastChild !== node && last(lastChild.leadingComments).end <= node.start) {
88 node.leadingComments = lastChild.leadingComments;
89 lastChild.leadingComments = null;
90 } else {
91 // A leading comment for an anonymous class had been stolen by its first ClassMethod,
92 // so this takes back the leading comment.
93 // See also: https://github.com/eslint/espree/issues/158
94 for (i = lastChild.leadingComments.length - 2; i >= 0; --i) {
95 if (lastChild.leadingComments[i].end <= node.start) {
96 node.leadingComments = lastChild.leadingComments.splice(0, i + 1);
97 break;
98 }
99 }
100 }
101 }
102 } else if (this.state.leadingComments.length > 0) {
103 if (last(this.state.leadingComments).end <= node.start) {
104 node.leadingComments = this.state.leadingComments;
105 this.state.leadingComments = [];
106 } else {
107 // https://github.com/eslint/espree/issues/2
108 //
109 // In special cases, such as return (without a value) and
110 // debugger, all comments will end up as leadingComments and
111 // will otherwise be eliminated. This step runs when the
112 // commentStack is empty and there are comments left
113 // in leadingComments.
114 //
115 // This loop figures out the stopping point between the actual
116 // leading and trailing comments by finding the location of the
117 // first comment that comes after the given node.
118 for (i = 0; i < this.state.leadingComments.length; i++) {
119 if (this.state.leadingComments[i].end > node.start) {
120 break;
121 }
122 }
123
124 // Split the array based on the location of the first comment
125 // that comes after the node. Keep in mind that this could
126 // result in an empty array, and if so, the array must be
127 // deleted.
128 node.leadingComments = this.state.leadingComments.slice(0, i);
129 if (node.leadingComments.length === 0) {
130 node.leadingComments = null;
131 }
132
133 // Similarly, trailing comments are attached later. The variable
134 // must be reset to null if there are no trailing comments.
135 trailingComments = this.state.leadingComments.slice(i);
136 if (trailingComments.length === 0) {
137 trailingComments = null;
138 }
139 }
140 }
141
142 if (trailingComments) {
143 if (trailingComments.length && trailingComments[0].start >= node.start && last(trailingComments).end <= node.end) {
144 node.innerComments = trailingComments;
145 } else {
146 node.trailingComments = trailingComments;
147 }
148 }
149
150 stack.push(node);
151};
\No newline at end of file