Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80738 views
1
define(
2
["./visitor","exports"],
3
function(__dependency1__, __exports__) {
4
"use strict";
5
var Visitor = __dependency1__["default"];
6
7
function WhitespaceControl() {
8
}
9
WhitespaceControl.prototype = new Visitor();
10
11
WhitespaceControl.prototype.Program = function(program) {
12
var isRoot = !this.isRootSeen;
13
this.isRootSeen = true;
14
15
var body = program.body;
16
for (var i = 0, l = body.length; i < l; i++) {
17
var current = body[i],
18
strip = this.accept(current);
19
20
if (!strip) {
21
continue;
22
}
23
24
var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
25
_isNextWhitespace = isNextWhitespace(body, i, isRoot),
26
27
openStandalone = strip.openStandalone && _isPrevWhitespace,
28
closeStandalone = strip.closeStandalone && _isNextWhitespace,
29
inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;
30
31
if (strip.close) {
32
omitRight(body, i, true);
33
}
34
if (strip.open) {
35
omitLeft(body, i, true);
36
}
37
38
if (inlineStandalone) {
39
omitRight(body, i);
40
41
if (omitLeft(body, i)) {
42
// If we are on a standalone node, save the indent info for partials
43
if (current.type === 'PartialStatement') {
44
// Pull out the whitespace from the final line
45
current.indent = (/([ \t]+$)/).exec(body[i-1].original)[1];
46
}
47
}
48
}
49
if (openStandalone) {
50
omitRight((current.program || current.inverse).body);
51
52
// Strip out the previous content node if it's whitespace only
53
omitLeft(body, i);
54
}
55
if (closeStandalone) {
56
// Always strip the next node
57
omitRight(body, i);
58
59
omitLeft((current.inverse || current.program).body);
60
}
61
}
62
63
return program;
64
};
65
WhitespaceControl.prototype.BlockStatement = function(block) {
66
this.accept(block.program);
67
this.accept(block.inverse);
68
69
// Find the inverse program that is involed with whitespace stripping.
70
var program = block.program || block.inverse,
71
inverse = block.program && block.inverse,
72
firstInverse = inverse,
73
lastInverse = inverse;
74
75
if (inverse && inverse.chained) {
76
firstInverse = inverse.body[0].program;
77
78
// Walk the inverse chain to find the last inverse that is actually in the chain.
79
while (lastInverse.chained) {
80
lastInverse = lastInverse.body[lastInverse.body.length-1].program;
81
}
82
}
83
84
var strip = {
85
open: block.openStrip.open,
86
close: block.closeStrip.close,
87
88
// Determine the standalone candiacy. Basically flag our content as being possibly standalone
89
// so our parent can determine if we actually are standalone
90
openStandalone: isNextWhitespace(program.body),
91
closeStandalone: isPrevWhitespace((firstInverse || program).body)
92
};
93
94
if (block.openStrip.close) {
95
omitRight(program.body, null, true);
96
}
97
98
if (inverse) {
99
var inverseStrip = block.inverseStrip;
100
101
if (inverseStrip.open) {
102
omitLeft(program.body, null, true);
103
}
104
105
if (inverseStrip.close) {
106
omitRight(firstInverse.body, null, true);
107
}
108
if (block.closeStrip.open) {
109
omitLeft(lastInverse.body, null, true);
110
}
111
112
// Find standalone else statments
113
if (isPrevWhitespace(program.body)
114
&& isNextWhitespace(firstInverse.body)) {
115
116
omitLeft(program.body);
117
omitRight(firstInverse.body);
118
}
119
} else {
120
if (block.closeStrip.open) {
121
omitLeft(program.body, null, true);
122
}
123
}
124
125
return strip;
126
};
127
128
WhitespaceControl.prototype.MustacheStatement = function(mustache) {
129
return mustache.strip;
130
};
131
132
WhitespaceControl.prototype.PartialStatement =
133
WhitespaceControl.prototype.CommentStatement = function(node) {
134
/* istanbul ignore next */
135
var strip = node.strip || {};
136
return {
137
inlineStandalone: true,
138
open: strip.open,
139
close: strip.close
140
};
141
};
142
143
144
function isPrevWhitespace(body, i, isRoot) {
145
if (i === undefined) {
146
i = body.length;
147
}
148
149
// Nodes that end with newlines are considered whitespace (but are special
150
// cased for strip operations)
151
var prev = body[i-1],
152
sibling = body[i-2];
153
if (!prev) {
154
return isRoot;
155
}
156
157
if (prev.type === 'ContentStatement') {
158
return (sibling || !isRoot ? (/\r?\n\s*?$/) : (/(^|\r?\n)\s*?$/)).test(prev.original);
159
}
160
}
161
function isNextWhitespace(body, i, isRoot) {
162
if (i === undefined) {
163
i = -1;
164
}
165
166
var next = body[i+1],
167
sibling = body[i+2];
168
if (!next) {
169
return isRoot;
170
}
171
172
if (next.type === 'ContentStatement') {
173
return (sibling || !isRoot ? (/^\s*?\r?\n/) : (/^\s*?(\r?\n|$)/)).test(next.original);
174
}
175
}
176
177
// Marks the node to the right of the position as omitted.
178
// I.e. {{foo}}' ' will mark the ' ' node as omitted.
179
//
180
// If i is undefined, then the first child will be marked as such.
181
//
182
// If mulitple is truthy then all whitespace will be stripped out until non-whitespace
183
// content is met.
184
function omitRight(body, i, multiple) {
185
var current = body[i == null ? 0 : i + 1];
186
if (!current || current.type !== 'ContentStatement' || (!multiple && current.rightStripped)) {
187
return;
188
}
189
190
var original = current.value;
191
current.value = current.value.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), '');
192
current.rightStripped = current.value !== original;
193
}
194
195
// Marks the node to the left of the position as omitted.
196
// I.e. ' '{{foo}} will mark the ' ' node as omitted.
197
//
198
// If i is undefined then the last child will be marked as such.
199
//
200
// If mulitple is truthy then all whitespace will be stripped out until non-whitespace
201
// content is met.
202
function omitLeft(body, i, multiple) {
203
var current = body[i == null ? body.length - 1 : i - 1];
204
if (!current || current.type !== 'ContentStatement' || (!multiple && current.leftStripped)) {
205
return;
206
}
207
208
// We omit the last node if it's whitespace only and not preceeded by a non-content node.
209
var original = current.value;
210
current.value = current.value.replace(multiple ? (/\s+$/) : (/[ \t]+$/), '');
211
current.leftStripped = current.value !== original;
212
return current.leftStripped;
213
}
214
215
__exports__["default"] = WhitespaceControl;
216
});
217