UNPKG

22.1 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7var _buffer = require("./buffer.js");
8var n = require("./node/index.js");
9var _t = require("@babel/types");
10var generatorFunctions = require("./generators/index.js");
11const {
12 isFunction,
13 isStatement,
14 isClassBody,
15 isTSInterfaceBody,
16 isTSEnumDeclaration
17} = _t;
18const SCIENTIFIC_NOTATION = /e/i;
19const ZERO_DECIMAL_INTEGER = /\.0+$/;
20const HAS_NEWLINE = /[\n\r\u2028\u2029]/;
21const HAS_NEWLINE_OR_BlOCK_COMMENT_END = /[\n\r\u2028\u2029]|\*\//;
22const {
23 needsParens
24} = n;
25class Printer {
26 constructor(format, map) {
27 this.inForStatementInitCounter = 0;
28 this._printStack = [];
29 this._indent = 0;
30 this._indentRepeat = 0;
31 this._insideAux = false;
32 this._parenPushNewlineState = null;
33 this._noLineTerminator = false;
34 this._printAuxAfterOnNextUserNode = false;
35 this._printedComments = new Set();
36 this._endsWithInteger = false;
37 this._endsWithWord = false;
38 this._lastCommentLine = 0;
39 this._endsWithInnerRaw = false;
40 this._indentInnerComments = true;
41 this.format = format;
42 this._indentRepeat = format.indent.style.length;
43 this._inputMap = map == null ? void 0 : map._inputMap;
44 this._buf = new _buffer.default(map, format.indent.style[0]);
45 }
46 generate(ast) {
47 this.print(ast);
48 this._maybeAddAuxComment();
49 return this._buf.get();
50 }
51 indent() {
52 if (this.format.compact || this.format.concise) return;
53 this._indent++;
54 }
55 dedent() {
56 if (this.format.compact || this.format.concise) return;
57 this._indent--;
58 }
59 semicolon(force = false) {
60 this._maybeAddAuxComment();
61 if (force) {
62 this._appendChar(59);
63 } else {
64 this._queue(59);
65 }
66 this._noLineTerminator = false;
67 }
68 rightBrace(node) {
69 if (this.format.minified) {
70 this._buf.removeLastSemicolon();
71 }
72 this.sourceWithOffset("end", node.loc, -1);
73 this.tokenChar(125);
74 }
75 rightParens(node) {
76 this.sourceWithOffset("end", node.loc, -1);
77 this.tokenChar(41);
78 }
79 space(force = false) {
80 if (this.format.compact) return;
81 if (force) {
82 this._space();
83 } else if (this._buf.hasContent()) {
84 const lastCp = this.getLastChar();
85 if (lastCp !== 32 && lastCp !== 10) {
86 this._space();
87 }
88 }
89 }
90 word(str, noLineTerminatorAfter = false) {
91 this._maybePrintInnerComments();
92 if (this._endsWithWord || str.charCodeAt(0) === 47 && this.endsWith(47)) {
93 this._space();
94 }
95 this._maybeAddAuxComment();
96 this._append(str, false);
97 this._endsWithWord = true;
98 this._noLineTerminator = noLineTerminatorAfter;
99 }
100 number(str, number) {
101 function isNonDecimalLiteral(str) {
102 if (str.length > 2 && str.charCodeAt(0) === 48) {
103 const secondChar = str.charCodeAt(1);
104 return secondChar === 98 || secondChar === 111 || secondChar === 120;
105 }
106 return false;
107 }
108 this.word(str);
109 this._endsWithInteger = Number.isInteger(number) && !isNonDecimalLiteral(str) && !SCIENTIFIC_NOTATION.test(str) && !ZERO_DECIMAL_INTEGER.test(str) && str.charCodeAt(str.length - 1) !== 46;
110 }
111 token(str, maybeNewline = false) {
112 this._maybePrintInnerComments();
113 const lastChar = this.getLastChar();
114 const strFirst = str.charCodeAt(0);
115 if (lastChar === 33 && (str === "--" || strFirst === 61) || strFirst === 43 && lastChar === 43 || strFirst === 45 && lastChar === 45 || strFirst === 46 && this._endsWithInteger) {
116 this._space();
117 }
118 this._maybeAddAuxComment();
119 this._append(str, maybeNewline);
120 this._noLineTerminator = false;
121 }
122 tokenChar(char) {
123 this._maybePrintInnerComments();
124 const lastChar = this.getLastChar();
125 if (char === 43 && lastChar === 43 || char === 45 && lastChar === 45 || char === 46 && this._endsWithInteger) {
126 this._space();
127 }
128 this._maybeAddAuxComment();
129 this._appendChar(char);
130 this._noLineTerminator = false;
131 }
132 newline(i = 1, force) {
133 if (i <= 0) return;
134 if (!force) {
135 if (this.format.retainLines || this.format.compact) return;
136 if (this.format.concise) {
137 this.space();
138 return;
139 }
140 }
141 if (i > 2) i = 2;
142 i -= this._buf.getNewlineCount();
143 for (let j = 0; j < i; j++) {
144 this._newline();
145 }
146 return;
147 }
148 endsWith(char) {
149 return this.getLastChar() === char;
150 }
151 getLastChar() {
152 return this._buf.getLastChar();
153 }
154 endsWithCharAndNewline() {
155 return this._buf.endsWithCharAndNewline();
156 }
157 removeTrailingNewline() {
158 this._buf.removeTrailingNewline();
159 }
160 exactSource(loc, cb) {
161 if (!loc) {
162 cb();
163 return;
164 }
165 this._catchUp("start", loc);
166 this._buf.exactSource(loc, cb);
167 }
168 source(prop, loc) {
169 if (!loc) return;
170 this._catchUp(prop, loc);
171 this._buf.source(prop, loc);
172 }
173 sourceWithOffset(prop, loc, columnOffset) {
174 if (!loc) return;
175 this._catchUp(prop, loc);
176 this._buf.sourceWithOffset(prop, loc, columnOffset);
177 }
178 withSource(prop, loc, cb) {
179 if (!loc) {
180 cb();
181 return;
182 }
183 this._catchUp(prop, loc);
184 this._buf.withSource(prop, loc, cb);
185 }
186 sourceIdentifierName(identifierName, pos) {
187 if (!this._buf._canMarkIdName) return;
188 const sourcePosition = this._buf._sourcePosition;
189 sourcePosition.identifierNamePos = pos;
190 sourcePosition.identifierName = identifierName;
191 }
192 _space() {
193 this._queue(32);
194 }
195 _newline() {
196 this._queue(10);
197 }
198 _append(str, maybeNewline) {
199 this._maybeAddParen(str);
200 this._maybeIndent(str.charCodeAt(0));
201 this._buf.append(str, maybeNewline);
202 this._endsWithWord = false;
203 this._endsWithInteger = false;
204 }
205 _appendChar(char) {
206 this._maybeAddParenChar(char);
207 this._maybeIndent(char);
208 this._buf.appendChar(char);
209 this._endsWithWord = false;
210 this._endsWithInteger = false;
211 }
212 _queue(char) {
213 this._maybeAddParenChar(char);
214 this._maybeIndent(char);
215 this._buf.queue(char);
216 this._endsWithWord = false;
217 this._endsWithInteger = false;
218 }
219 _maybeIndent(firstChar) {
220 if (this._indent && firstChar !== 10 && this.endsWith(10)) {
221 this._buf.queueIndentation(this._getIndent());
222 }
223 }
224 _shouldIndent(firstChar) {
225 if (this._indent && firstChar !== 10 && this.endsWith(10)) {
226 return true;
227 }
228 }
229 _maybeAddParenChar(char) {
230 const parenPushNewlineState = this._parenPushNewlineState;
231 if (!parenPushNewlineState) return;
232 if (char === 32) {
233 return;
234 }
235 if (char !== 10) {
236 this._parenPushNewlineState = null;
237 return;
238 }
239 this.tokenChar(40);
240 this.indent();
241 parenPushNewlineState.printed = true;
242 }
243 _maybeAddParen(str) {
244 const parenPushNewlineState = this._parenPushNewlineState;
245 if (!parenPushNewlineState) return;
246 const len = str.length;
247 let i;
248 for (i = 0; i < len && str.charCodeAt(i) === 32; i++) continue;
249 if (i === len) {
250 return;
251 }
252 const cha = str.charCodeAt(i);
253 if (cha !== 10) {
254 if (cha !== 47 || i + 1 === len) {
255 this._parenPushNewlineState = null;
256 return;
257 }
258 const chaPost = str.charCodeAt(i + 1);
259 if (chaPost === 42) {
260 return;
261 } else if (chaPost !== 47) {
262 this._parenPushNewlineState = null;
263 return;
264 }
265 }
266 this.tokenChar(40);
267 this.indent();
268 parenPushNewlineState.printed = true;
269 }
270 catchUp(line) {
271 if (!this.format.retainLines) return;
272 const count = line - this._buf.getCurrentLine();
273 for (let i = 0; i < count; i++) {
274 this._newline();
275 }
276 }
277 _catchUp(prop, loc) {
278 var _loc$prop;
279 if (!this.format.retainLines) return;
280 const line = loc == null || (_loc$prop = loc[prop]) == null ? void 0 : _loc$prop.line;
281 if (line != null) {
282 const count = line - this._buf.getCurrentLine();
283 for (let i = 0; i < count; i++) {
284 this._newline();
285 }
286 }
287 }
288 _getIndent() {
289 return this._indentRepeat * this._indent;
290 }
291 printTerminatorless(node, parent, isLabel) {
292 if (isLabel) {
293 this._noLineTerminator = true;
294 this.print(node, parent);
295 } else {
296 const terminatorState = {
297 printed: false
298 };
299 this._parenPushNewlineState = terminatorState;
300 this.print(node, parent);
301 if (terminatorState.printed) {
302 this.dedent();
303 this.newline();
304 this.tokenChar(41);
305 }
306 }
307 }
308 print(node, parent, noLineTerminatorAfter, trailingCommentsLineOffset, forceParens) {
309 var _node$extra, _node$leadingComments;
310 if (!node) return;
311 this._endsWithInnerRaw = false;
312 const nodeType = node.type;
313 const format = this.format;
314 const oldConcise = format.concise;
315 if (node._compact) {
316 format.concise = true;
317 }
318 const printMethod = this[nodeType];
319 if (printMethod === undefined) {
320 throw new ReferenceError(`unknown node of type ${JSON.stringify(nodeType)} with constructor ${JSON.stringify(node.constructor.name)}`);
321 }
322 this._printStack.push(node);
323 const oldInAux = this._insideAux;
324 this._insideAux = node.loc == null;
325 this._maybeAddAuxComment(this._insideAux && !oldInAux);
326 const parenthesized = (_node$extra = node.extra) == null ? void 0 : _node$extra.parenthesized;
327 let shouldPrintParens = forceParens || parenthesized && format.retainFunctionParens && nodeType === "FunctionExpression" || needsParens(node, parent, this._printStack);
328 if (!shouldPrintParens && parenthesized && (_node$leadingComments = node.leadingComments) != null && _node$leadingComments.length && node.leadingComments[0].type === "CommentBlock") {
329 const parentType = parent == null ? void 0 : parent.type;
330 switch (parentType) {
331 case "ExpressionStatement":
332 case "VariableDeclarator":
333 case "AssignmentExpression":
334 case "ReturnStatement":
335 break;
336 case "CallExpression":
337 case "OptionalCallExpression":
338 case "NewExpression":
339 if (parent.callee !== node) break;
340 default:
341 shouldPrintParens = true;
342 }
343 }
344 if (shouldPrintParens) {
345 this.tokenChar(40);
346 this._endsWithInnerRaw = false;
347 }
348 this._lastCommentLine = 0;
349 this._printLeadingComments(node, parent);
350 const loc = nodeType === "Program" || nodeType === "File" ? null : node.loc;
351 this.exactSource(loc, printMethod.bind(this, node, parent));
352 if (shouldPrintParens) {
353 this._printTrailingComments(node, parent);
354 this.tokenChar(41);
355 this._noLineTerminator = noLineTerminatorAfter;
356 } else if (noLineTerminatorAfter && !this._noLineTerminator) {
357 this._noLineTerminator = true;
358 this._printTrailingComments(node, parent);
359 } else {
360 this._printTrailingComments(node, parent, trailingCommentsLineOffset);
361 }
362 this._printStack.pop();
363 format.concise = oldConcise;
364 this._insideAux = oldInAux;
365 this._endsWithInnerRaw = false;
366 }
367 _maybeAddAuxComment(enteredPositionlessNode) {
368 if (enteredPositionlessNode) this._printAuxBeforeComment();
369 if (!this._insideAux) this._printAuxAfterComment();
370 }
371 _printAuxBeforeComment() {
372 if (this._printAuxAfterOnNextUserNode) return;
373 this._printAuxAfterOnNextUserNode = true;
374 const comment = this.format.auxiliaryCommentBefore;
375 if (comment) {
376 this._printComment({
377 type: "CommentBlock",
378 value: comment
379 }, 0);
380 }
381 }
382 _printAuxAfterComment() {
383 if (!this._printAuxAfterOnNextUserNode) return;
384 this._printAuxAfterOnNextUserNode = false;
385 const comment = this.format.auxiliaryCommentAfter;
386 if (comment) {
387 this._printComment({
388 type: "CommentBlock",
389 value: comment
390 }, 0);
391 }
392 }
393 getPossibleRaw(node) {
394 const extra = node.extra;
395 if ((extra == null ? void 0 : extra.raw) != null && extra.rawValue != null && node.value === extra.rawValue) {
396 return extra.raw;
397 }
398 }
399 printJoin(nodes, parent, opts = {}) {
400 if (!(nodes != null && nodes.length)) return;
401 let {
402 indent
403 } = opts;
404 if (indent == null && this.format.retainLines) {
405 var _nodes$0$loc;
406 const startLine = (_nodes$0$loc = nodes[0].loc) == null ? void 0 : _nodes$0$loc.start.line;
407 if (startLine != null && startLine !== this._buf.getCurrentLine()) {
408 indent = true;
409 }
410 }
411 if (indent) this.indent();
412 const newlineOpts = {
413 addNewlines: opts.addNewlines,
414 nextNodeStartLine: 0
415 };
416 const separator = opts.separator ? opts.separator.bind(this) : null;
417 const len = nodes.length;
418 for (let i = 0; i < len; i++) {
419 const node = nodes[i];
420 if (!node) continue;
421 if (opts.statement) this._printNewline(i === 0, newlineOpts);
422 this.print(node, parent, undefined, opts.trailingCommentsLineOffset || 0);
423 opts.iterator == null || opts.iterator(node, i);
424 if (i < len - 1) separator == null || separator();
425 if (opts.statement) {
426 var _node$trailingComment;
427 if (!((_node$trailingComment = node.trailingComments) != null && _node$trailingComment.length)) {
428 this._lastCommentLine = 0;
429 }
430 if (i + 1 === len) {
431 this.newline(1);
432 } else {
433 var _nextNode$loc;
434 const nextNode = nodes[i + 1];
435 newlineOpts.nextNodeStartLine = ((_nextNode$loc = nextNode.loc) == null ? void 0 : _nextNode$loc.start.line) || 0;
436 this._printNewline(true, newlineOpts);
437 }
438 }
439 }
440 if (indent) this.dedent();
441 }
442 printAndIndentOnComments(node, parent) {
443 const indent = node.leadingComments && node.leadingComments.length > 0;
444 if (indent) this.indent();
445 this.print(node, parent);
446 if (indent) this.dedent();
447 }
448 printBlock(parent) {
449 const node = parent.body;
450 if (node.type !== "EmptyStatement") {
451 this.space();
452 }
453 this.print(node, parent);
454 }
455 _printTrailingComments(node, parent, lineOffset) {
456 const {
457 innerComments,
458 trailingComments
459 } = node;
460 if (innerComments != null && innerComments.length) {
461 this._printComments(2, innerComments, node, parent, lineOffset);
462 }
463 if (trailingComments != null && trailingComments.length) {
464 this._printComments(2, trailingComments, node, parent, lineOffset);
465 }
466 }
467 _printLeadingComments(node, parent) {
468 const comments = node.leadingComments;
469 if (!(comments != null && comments.length)) return;
470 this._printComments(0, comments, node, parent);
471 }
472 _maybePrintInnerComments() {
473 if (this._endsWithInnerRaw) this.printInnerComments();
474 this._endsWithInnerRaw = true;
475 this._indentInnerComments = true;
476 }
477 printInnerComments() {
478 const node = this._printStack[this._printStack.length - 1];
479 const comments = node.innerComments;
480 if (!(comments != null && comments.length)) return;
481 const hasSpace = this.endsWith(32);
482 const indent = this._indentInnerComments;
483 const printedCommentsCount = this._printedComments.size;
484 if (indent) this.indent();
485 this._printComments(1, comments, node);
486 if (hasSpace && printedCommentsCount !== this._printedComments.size) {
487 this.space();
488 }
489 if (indent) this.dedent();
490 }
491 noIndentInnerCommentsHere() {
492 this._indentInnerComments = false;
493 }
494 printSequence(nodes, parent, opts = {}) {
495 var _opts$indent;
496 opts.statement = true;
497 (_opts$indent = opts.indent) != null ? _opts$indent : opts.indent = false;
498 this.printJoin(nodes, parent, opts);
499 }
500 printList(items, parent, opts = {}) {
501 if (opts.separator == null) {
502 opts.separator = commaSeparator;
503 }
504 this.printJoin(items, parent, opts);
505 }
506 _printNewline(newLine, opts) {
507 const format = this.format;
508 if (format.retainLines || format.compact) return;
509 if (format.concise) {
510 this.space();
511 return;
512 }
513 if (!newLine) {
514 return;
515 }
516 const startLine = opts.nextNodeStartLine;
517 const lastCommentLine = this._lastCommentLine;
518 if (startLine > 0 && lastCommentLine > 0) {
519 const offset = startLine - lastCommentLine;
520 if (offset >= 0) {
521 this.newline(offset || 1);
522 return;
523 }
524 }
525 if (this._buf.hasContent()) {
526 this.newline(1);
527 }
528 }
529 _shouldPrintComment(comment) {
530 if (comment.ignore) return 0;
531 if (this._printedComments.has(comment)) return 0;
532 if (this._noLineTerminator && HAS_NEWLINE_OR_BlOCK_COMMENT_END.test(comment.value)) {
533 return 2;
534 }
535 this._printedComments.add(comment);
536 if (!this.format.shouldPrintComment(comment.value)) {
537 return 0;
538 }
539 return 1;
540 }
541 _printComment(comment, skipNewLines) {
542 const noLineTerminator = this._noLineTerminator;
543 const isBlockComment = comment.type === "CommentBlock";
544 const printNewLines = isBlockComment && skipNewLines !== 1 && !this._noLineTerminator;
545 if (printNewLines && this._buf.hasContent() && skipNewLines !== 2) {
546 this.newline(1);
547 }
548 const lastCharCode = this.getLastChar();
549 if (lastCharCode !== 91 && lastCharCode !== 123) {
550 this.space();
551 }
552 let val;
553 if (isBlockComment) {
554 const {
555 _parenPushNewlineState
556 } = this;
557 if ((_parenPushNewlineState == null ? void 0 : _parenPushNewlineState.printed) === false && HAS_NEWLINE.test(comment.value)) {
558 this.tokenChar(40);
559 this.indent();
560 _parenPushNewlineState.printed = true;
561 }
562 val = `/*${comment.value}*/`;
563 if (this.format.indent.adjustMultilineComment) {
564 var _comment$loc;
565 const offset = (_comment$loc = comment.loc) == null ? void 0 : _comment$loc.start.column;
566 if (offset) {
567 const newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
568 val = val.replace(newlineRegex, "\n");
569 }
570 if (this.format.concise) {
571 val = val.replace(/\n(?!$)/g, `\n`);
572 } else {
573 let indentSize = this.format.retainLines ? 0 : this._buf.getCurrentColumn();
574 if (this._shouldIndent(47) || this.format.retainLines) {
575 indentSize += this._getIndent();
576 }
577 val = val.replace(/\n(?!$)/g, `\n${" ".repeat(indentSize)}`);
578 }
579 }
580 } else if (!noLineTerminator) {
581 val = `//${comment.value}`;
582 } else {
583 val = `/*${comment.value}*/`;
584 }
585 if (this.endsWith(47)) this._space();
586 this.source("start", comment.loc);
587 this._append(val, isBlockComment);
588 if (!isBlockComment && !noLineTerminator) {
589 this.newline(1, true);
590 }
591 if (printNewLines && skipNewLines !== 3) {
592 this.newline(1);
593 }
594 }
595 _printComments(type, comments, node, parent, lineOffset = 0) {
596 const nodeLoc = node.loc;
597 const len = comments.length;
598 let hasLoc = !!nodeLoc;
599 const nodeStartLine = hasLoc ? nodeLoc.start.line : 0;
600 const nodeEndLine = hasLoc ? nodeLoc.end.line : 0;
601 let lastLine = 0;
602 let leadingCommentNewline = 0;
603 const maybeNewline = this._noLineTerminator ? function () {} : this.newline.bind(this);
604 for (let i = 0; i < len; i++) {
605 const comment = comments[i];
606 const shouldPrint = this._shouldPrintComment(comment);
607 if (shouldPrint === 2) {
608 hasLoc = false;
609 break;
610 }
611 if (hasLoc && comment.loc && shouldPrint === 1) {
612 const commentStartLine = comment.loc.start.line;
613 const commentEndLine = comment.loc.end.line;
614 if (type === 0) {
615 let offset = 0;
616 if (i === 0) {
617 if (this._buf.hasContent() && (comment.type === "CommentLine" || commentStartLine !== commentEndLine)) {
618 offset = leadingCommentNewline = 1;
619 }
620 } else {
621 offset = commentStartLine - lastLine;
622 }
623 lastLine = commentEndLine;
624 maybeNewline(offset);
625 this._printComment(comment, 1);
626 if (i + 1 === len) {
627 maybeNewline(Math.max(nodeStartLine - lastLine, leadingCommentNewline));
628 lastLine = nodeStartLine;
629 }
630 } else if (type === 1) {
631 const offset = commentStartLine - (i === 0 ? nodeStartLine : lastLine);
632 lastLine = commentEndLine;
633 maybeNewline(offset);
634 this._printComment(comment, 1);
635 if (i + 1 === len) {
636 maybeNewline(Math.min(1, nodeEndLine - lastLine));
637 lastLine = nodeEndLine;
638 }
639 } else {
640 const offset = commentStartLine - (i === 0 ? nodeEndLine - lineOffset : lastLine);
641 lastLine = commentEndLine;
642 maybeNewline(offset);
643 this._printComment(comment, 1);
644 }
645 } else {
646 hasLoc = false;
647 if (shouldPrint !== 1) {
648 continue;
649 }
650 if (len === 1) {
651 const singleLine = comment.loc ? comment.loc.start.line === comment.loc.end.line : !HAS_NEWLINE.test(comment.value);
652 const shouldSkipNewline = singleLine && !isStatement(node) && !isClassBody(parent) && !isTSInterfaceBody(parent) && !isTSEnumDeclaration(parent);
653 if (type === 0) {
654 this._printComment(comment, shouldSkipNewline && node.type !== "ObjectExpression" || singleLine && isFunction(parent, {
655 body: node
656 }) ? 1 : 0);
657 } else if (shouldSkipNewline && type === 2) {
658 this._printComment(comment, 1);
659 } else {
660 this._printComment(comment, 0);
661 }
662 } else if (type === 1 && !(node.type === "ObjectExpression" && node.properties.length > 1) && node.type !== "ClassBody" && node.type !== "TSInterfaceBody") {
663 this._printComment(comment, i === 0 ? 2 : i === len - 1 ? 3 : 0);
664 } else {
665 this._printComment(comment, 0);
666 }
667 }
668 }
669 if (type === 2 && hasLoc && lastLine) {
670 this._lastCommentLine = lastLine;
671 }
672 }
673}
674Object.assign(Printer.prototype, generatorFunctions);
675{
676 Printer.prototype.Noop = function Noop() {};
677}
678var _default = exports.default = Printer;
679function commaSeparator() {
680 this.tokenChar(44);
681 this.space();
682}
683
684//# sourceMappingURL=printer.js.map