UNPKG

12.7 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _buffer = require("./buffer");
9
10var n = require("./node");
11
12var t = require("@babel/types");
13
14var generatorFunctions = require("./generators");
15
16const SCIENTIFIC_NOTATION = /e/i;
17const ZERO_DECIMAL_INTEGER = /\.0+$/;
18const NON_DECIMAL_LITERAL = /^0[box]/;
19const PURE_ANNOTATION_RE = /^\s*[@#]__PURE__\s*$/;
20const {
21 isProgram,
22 isFile,
23 isEmptyStatement
24} = t;
25const {
26 needsParens,
27 needsWhitespaceAfter,
28 needsWhitespaceBefore
29} = n;
30
31class Printer {
32 constructor(format, map) {
33 this.inForStatementInitCounter = 0;
34 this._printStack = [];
35 this._indent = 0;
36 this._insideAux = false;
37 this._parenPushNewlineState = null;
38 this._noLineTerminator = false;
39 this._printAuxAfterOnNextUserNode = false;
40 this._printedComments = new WeakSet();
41 this._endsWithInteger = false;
42 this._endsWithWord = false;
43 this.format = format;
44 this._buf = new _buffer.default(map);
45 }
46
47 generate(ast) {
48 this.print(ast);
49
50 this._maybeAddAuxComment();
51
52 return this._buf.get();
53 }
54
55 indent() {
56 if (this.format.compact || this.format.concise) return;
57 this._indent++;
58 }
59
60 dedent() {
61 if (this.format.compact || this.format.concise) return;
62 this._indent--;
63 }
64
65 semicolon(force = false) {
66 this._maybeAddAuxComment();
67
68 this._append(";", !force);
69 }
70
71 rightBrace() {
72 if (this.format.minified) {
73 this._buf.removeLastSemicolon();
74 }
75
76 this.token("}");
77 }
78
79 space(force = false) {
80 if (this.format.compact) return;
81
82 if (force) {
83 this._space();
84 } else if (this._buf.hasContent()) {
85 const lastCp = this.getLastChar();
86
87 if (lastCp !== 32 && lastCp !== 10) {
88 this._space();
89 }
90 }
91 }
92
93 word(str) {
94 if (this._endsWithWord || this.endsWith(47) && str.charCodeAt(0) === 47) {
95 this._space();
96 }
97
98 this._maybeAddAuxComment();
99
100 this._append(str);
101
102 this._endsWithWord = true;
103 }
104
105 number(str) {
106 this.word(str);
107 this._endsWithInteger = Number.isInteger(+str) && !NON_DECIMAL_LITERAL.test(str) && !SCIENTIFIC_NOTATION.test(str) && !ZERO_DECIMAL_INTEGER.test(str) && str.charCodeAt(str.length - 1) !== 46;
108 }
109
110 token(str) {
111 const lastChar = this.getLastChar();
112 const strFirst = str.charCodeAt(0);
113
114 if (str === "--" && lastChar === 33 || strFirst === 43 && lastChar === 43 || strFirst === 45 && lastChar === 45 || strFirst === 46 && this._endsWithInteger) {
115 this._space();
116 }
117
118 this._maybeAddAuxComment();
119
120 this._append(str);
121 }
122
123 newline(i = 1) {
124 if (this.format.retainLines || this.format.compact) return;
125
126 if (this.format.concise) {
127 this.space();
128 return;
129 }
130
131 const charBeforeNewline = this.endsWithCharAndNewline();
132 if (charBeforeNewline === 10) return;
133
134 if (charBeforeNewline === 123 || charBeforeNewline === 58) {
135 i--;
136 }
137
138 if (i <= 0) return;
139
140 for (let j = 0; j < i; j++) {
141 this._newline();
142 }
143 }
144
145 endsWith(char) {
146 return this.getLastChar() === char;
147 }
148
149 getLastChar() {
150 return this._buf.getLastChar();
151 }
152
153 endsWithCharAndNewline() {
154 return this._buf.endsWithCharAndNewline();
155 }
156
157 removeTrailingNewline() {
158 this._buf.removeTrailingNewline();
159 }
160
161 exactSource(loc, cb) {
162 this._catchUp("start", loc);
163
164 this._buf.exactSource(loc, cb);
165 }
166
167 source(prop, loc) {
168 this._catchUp(prop, loc);
169
170 this._buf.source(prop, loc);
171 }
172
173 withSource(prop, loc, cb) {
174 this._catchUp(prop, loc);
175
176 this._buf.withSource(prop, loc, cb);
177 }
178
179 _space() {
180 this._append(" ", true);
181 }
182
183 _newline() {
184 this._append("\n", true);
185 }
186
187 _append(str, queue = false) {
188 this._maybeAddParen(str);
189
190 this._maybeIndent(str);
191
192 if (queue) this._buf.queue(str);else this._buf.append(str);
193 this._endsWithWord = false;
194 this._endsWithInteger = false;
195 }
196
197 _maybeIndent(str) {
198 if (this._indent && this.endsWith(10) && str.charCodeAt(0) !== 10) {
199 this._buf.queue(this._getIndent());
200 }
201 }
202
203 _maybeAddParen(str) {
204 const parenPushNewlineState = this._parenPushNewlineState;
205 if (!parenPushNewlineState) return;
206 let i;
207
208 for (i = 0; i < str.length && str[i] === " "; i++) continue;
209
210 if (i === str.length) {
211 return;
212 }
213
214 const cha = str[i];
215
216 if (cha !== "\n") {
217 if (cha !== "/" || i + 1 === str.length) {
218 this._parenPushNewlineState = null;
219 return;
220 }
221
222 const chaPost = str[i + 1];
223
224 if (chaPost === "*") {
225 if (PURE_ANNOTATION_RE.test(str.slice(i + 2, str.length - 2))) {
226 return;
227 }
228 } else if (chaPost !== "/") {
229 this._parenPushNewlineState = null;
230 return;
231 }
232 }
233
234 this.token("(");
235 this.indent();
236 parenPushNewlineState.printed = true;
237 }
238
239 _catchUp(prop, loc) {
240 if (!this.format.retainLines) return;
241 const pos = loc ? loc[prop] : null;
242
243 if ((pos == null ? void 0 : pos.line) != null) {
244 const count = pos.line - this._buf.getCurrentLine();
245
246 for (let i = 0; i < count; i++) {
247 this._newline();
248 }
249 }
250 }
251
252 _getIndent() {
253 return this.format.indent.style.repeat(this._indent);
254 }
255
256 startTerminatorless(isLabel = false) {
257 if (isLabel) {
258 this._noLineTerminator = true;
259 return null;
260 } else {
261 return this._parenPushNewlineState = {
262 printed: false
263 };
264 }
265 }
266
267 endTerminatorless(state) {
268 this._noLineTerminator = false;
269
270 if (state != null && state.printed) {
271 this.dedent();
272 this.newline();
273 this.token(")");
274 }
275 }
276
277 print(node, parent) {
278 if (!node) return;
279 const oldConcise = this.format.concise;
280
281 if (node._compact) {
282 this.format.concise = true;
283 }
284
285 const printMethod = this[node.type];
286
287 if (!printMethod) {
288 throw new ReferenceError(`unknown node of type ${JSON.stringify(node.type)} with constructor ${JSON.stringify(node == null ? void 0 : node.constructor.name)}`);
289 }
290
291 this._printStack.push(node);
292
293 const oldInAux = this._insideAux;
294 this._insideAux = !node.loc;
295
296 this._maybeAddAuxComment(this._insideAux && !oldInAux);
297
298 let shouldPrintParens = needsParens(node, parent, this._printStack);
299
300 if (this.format.retainFunctionParens && node.type === "FunctionExpression" && node.extra && node.extra.parenthesized) {
301 shouldPrintParens = true;
302 }
303
304 if (shouldPrintParens) this.token("(");
305
306 this._printLeadingComments(node);
307
308 const loc = isProgram(node) || isFile(node) ? null : node.loc;
309 this.withSource("start", loc, () => {
310 printMethod.call(this, node, parent);
311 });
312
313 this._printTrailingComments(node);
314
315 if (shouldPrintParens) this.token(")");
316
317 this._printStack.pop();
318
319 this.format.concise = oldConcise;
320 this._insideAux = oldInAux;
321 }
322
323 _maybeAddAuxComment(enteredPositionlessNode) {
324 if (enteredPositionlessNode) this._printAuxBeforeComment();
325 if (!this._insideAux) this._printAuxAfterComment();
326 }
327
328 _printAuxBeforeComment() {
329 if (this._printAuxAfterOnNextUserNode) return;
330 this._printAuxAfterOnNextUserNode = true;
331 const comment = this.format.auxiliaryCommentBefore;
332
333 if (comment) {
334 this._printComment({
335 type: "CommentBlock",
336 value: comment
337 });
338 }
339 }
340
341 _printAuxAfterComment() {
342 if (!this._printAuxAfterOnNextUserNode) return;
343 this._printAuxAfterOnNextUserNode = false;
344 const comment = this.format.auxiliaryCommentAfter;
345
346 if (comment) {
347 this._printComment({
348 type: "CommentBlock",
349 value: comment
350 });
351 }
352 }
353
354 getPossibleRaw(node) {
355 const extra = node.extra;
356
357 if (extra && extra.raw != null && extra.rawValue != null && node.value === extra.rawValue) {
358 return extra.raw;
359 }
360 }
361
362 printJoin(nodes, parent, opts = {}) {
363 if (!(nodes != null && nodes.length)) return;
364 if (opts.indent) this.indent();
365 const newlineOpts = {
366 addNewlines: opts.addNewlines
367 };
368
369 for (let i = 0; i < nodes.length; i++) {
370 const node = nodes[i];
371 if (!node) continue;
372 if (opts.statement) this._printNewline(true, node, parent, newlineOpts);
373 this.print(node, parent);
374
375 if (opts.iterator) {
376 opts.iterator(node, i);
377 }
378
379 if (opts.separator && i < nodes.length - 1) {
380 opts.separator.call(this);
381 }
382
383 if (opts.statement) this._printNewline(false, node, parent, newlineOpts);
384 }
385
386 if (opts.indent) this.dedent();
387 }
388
389 printAndIndentOnComments(node, parent) {
390 const indent = node.leadingComments && node.leadingComments.length > 0;
391 if (indent) this.indent();
392 this.print(node, parent);
393 if (indent) this.dedent();
394 }
395
396 printBlock(parent) {
397 const node = parent.body;
398
399 if (!isEmptyStatement(node)) {
400 this.space();
401 }
402
403 this.print(node, parent);
404 }
405
406 _printTrailingComments(node) {
407 this._printComments(this._getComments(false, node));
408 }
409
410 _printLeadingComments(node) {
411 this._printComments(this._getComments(true, node), true);
412 }
413
414 printInnerComments(node, indent = true) {
415 var _node$innerComments;
416
417 if (!((_node$innerComments = node.innerComments) != null && _node$innerComments.length)) return;
418 if (indent) this.indent();
419
420 this._printComments(node.innerComments);
421
422 if (indent) this.dedent();
423 }
424
425 printSequence(nodes, parent, opts = {}) {
426 opts.statement = true;
427 return this.printJoin(nodes, parent, opts);
428 }
429
430 printList(items, parent, opts = {}) {
431 if (opts.separator == null) {
432 opts.separator = commaSeparator;
433 }
434
435 return this.printJoin(items, parent, opts);
436 }
437
438 _printNewline(leading, node, parent, opts) {
439 if (this.format.retainLines || this.format.compact) return;
440
441 if (this.format.concise) {
442 this.space();
443 return;
444 }
445
446 let lines = 0;
447
448 if (this._buf.hasContent()) {
449 if (!leading) lines++;
450 if (opts.addNewlines) lines += opts.addNewlines(leading, node) || 0;
451 const needs = leading ? needsWhitespaceBefore : needsWhitespaceAfter;
452 if (needs(node, parent)) lines++;
453 }
454
455 this.newline(Math.min(2, lines));
456 }
457
458 _getComments(leading, node) {
459 return node && (leading ? node.leadingComments : node.trailingComments) || [];
460 }
461
462 _printComment(comment, skipNewLines) {
463 if (!this.format.shouldPrintComment(comment.value)) return;
464 if (comment.ignore) return;
465 if (this._printedComments.has(comment)) return;
466
467 this._printedComments.add(comment);
468
469 const isBlockComment = comment.type === "CommentBlock";
470 const printNewLines = isBlockComment && !skipNewLines && !this._noLineTerminator;
471 if (printNewLines && this._buf.hasContent()) this.newline(1);
472 const lastCharCode = this.getLastChar();
473
474 if (lastCharCode !== 91 && lastCharCode !== 123) {
475 this.space();
476 }
477
478 let val = !isBlockComment && !this._noLineTerminator ? `//${comment.value}\n` : `/*${comment.value}*/`;
479
480 if (isBlockComment && this.format.indent.adjustMultilineComment) {
481 var _comment$loc;
482
483 const offset = (_comment$loc = comment.loc) == null ? void 0 : _comment$loc.start.column;
484
485 if (offset) {
486 const newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
487 val = val.replace(newlineRegex, "\n");
488 }
489
490 const indentSize = Math.max(this._getIndent().length, this.format.retainLines ? 0 : this._buf.getCurrentColumn());
491 val = val.replace(/\n(?!$)/g, `\n${" ".repeat(indentSize)}`);
492 }
493
494 if (this.endsWith(47)) this._space();
495 this.withSource("start", comment.loc, () => {
496 this._append(val);
497 });
498 if (printNewLines) this.newline(1);
499 }
500
501 _printComments(comments, inlinePureAnnotation) {
502 if (!(comments != null && comments.length)) return;
503
504 if (inlinePureAnnotation && comments.length === 1 && PURE_ANNOTATION_RE.test(comments[0].value)) {
505 this._printComment(comments[0], this._buf.hasContent() && !this.endsWith(10));
506 } else {
507 for (const comment of comments) {
508 this._printComment(comment);
509 }
510 }
511 }
512
513 printAssertions(node) {
514 var _node$assertions;
515
516 if ((_node$assertions = node.assertions) != null && _node$assertions.length) {
517 this.space();
518 this.word("assert");
519 this.space();
520 this.token("{");
521 this.space();
522 this.printList(node.assertions, node);
523 this.space();
524 this.token("}");
525 }
526 }
527
528}
529
530Object.assign(Printer.prototype, generatorFunctions);
531{
532 Printer.prototype.Noop = function Noop() {};
533}
534var _default = Printer;
535exports.default = _default;
536
537function commaSeparator() {
538 this.token(",");
539 this.space();
540}
\No newline at end of file