You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

478 lines
12 KiB

4 years ago
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _isInteger = _interopRequireDefault(require("lodash/isInteger"));
  7. var _repeat = _interopRequireDefault(require("lodash/repeat"));
  8. var _buffer = _interopRequireDefault(require("./buffer"));
  9. var n = _interopRequireWildcard(require("./node"));
  10. var t = _interopRequireWildcard(require("@babel/types"));
  11. var generatorFunctions = _interopRequireWildcard(require("./generators"));
  12. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
  13. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  14. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  15. const SCIENTIFIC_NOTATION = /e/i;
  16. const ZERO_DECIMAL_INTEGER = /\.0+$/;
  17. const NON_DECIMAL_LITERAL = /^0[box]/;
  18. class Printer {
  19. constructor(format, map) {
  20. this.inForStatementInitCounter = 0;
  21. this._printStack = [];
  22. this._indent = 0;
  23. this._insideAux = false;
  24. this._printedCommentStarts = {};
  25. this._parenPushNewlineState = null;
  26. this._noLineTerminator = false;
  27. this._printAuxAfterOnNextUserNode = false;
  28. this._printedComments = new WeakSet();
  29. this._endsWithInteger = false;
  30. this._endsWithWord = false;
  31. this.format = format || {};
  32. this._buf = new _buffer.default(map);
  33. }
  34. generate(ast) {
  35. this.print(ast);
  36. this._maybeAddAuxComment();
  37. return this._buf.get();
  38. }
  39. indent() {
  40. if (this.format.compact || this.format.concise) return;
  41. this._indent++;
  42. }
  43. dedent() {
  44. if (this.format.compact || this.format.concise) return;
  45. this._indent--;
  46. }
  47. semicolon(force = false) {
  48. this._maybeAddAuxComment();
  49. this._append(";", !force);
  50. }
  51. rightBrace() {
  52. if (this.format.minified) {
  53. this._buf.removeLastSemicolon();
  54. }
  55. this.token("}");
  56. }
  57. space(force = false) {
  58. if (this.format.compact) return;
  59. if (this._buf.hasContent() && !this.endsWith(" ") && !this.endsWith("\n") || force) {
  60. this._space();
  61. }
  62. }
  63. word(str) {
  64. if (this._endsWithWord || this.endsWith("/") && str.indexOf("/") === 0) {
  65. this._space();
  66. }
  67. this._maybeAddAuxComment();
  68. this._append(str);
  69. this._endsWithWord = true;
  70. }
  71. number(str) {
  72. this.word(str);
  73. this._endsWithInteger = (0, _isInteger.default)(+str) && !NON_DECIMAL_LITERAL.test(str) && !SCIENTIFIC_NOTATION.test(str) && !ZERO_DECIMAL_INTEGER.test(str) && str[str.length - 1] !== ".";
  74. }
  75. token(str) {
  76. if (str === "--" && this.endsWith("!") || str[0] === "+" && this.endsWith("+") || str[0] === "-" && this.endsWith("-") || str[0] === "." && this._endsWithInteger) {
  77. this._space();
  78. }
  79. this._maybeAddAuxComment();
  80. this._append(str);
  81. }
  82. newline(i) {
  83. if (this.format.retainLines || this.format.compact) return;
  84. if (this.format.concise) {
  85. this.space();
  86. return;
  87. }
  88. if (this.endsWith("\n\n")) return;
  89. if (typeof i !== "number") i = 1;
  90. i = Math.min(2, i);
  91. if (this.endsWith("{\n") || this.endsWith(":\n")) i--;
  92. if (i <= 0) return;
  93. for (let j = 0; j < i; j++) {
  94. this._newline();
  95. }
  96. }
  97. endsWith(str) {
  98. return this._buf.endsWith(str);
  99. }
  100. removeTrailingNewline() {
  101. this._buf.removeTrailingNewline();
  102. }
  103. exactSource(loc, cb) {
  104. this._catchUp("start", loc);
  105. this._buf.exactSource(loc, cb);
  106. }
  107. source(prop, loc) {
  108. this._catchUp(prop, loc);
  109. this._buf.source(prop, loc);
  110. }
  111. withSource(prop, loc, cb) {
  112. this._catchUp(prop, loc);
  113. this._buf.withSource(prop, loc, cb);
  114. }
  115. _space() {
  116. this._append(" ", true);
  117. }
  118. _newline() {
  119. this._append("\n", true);
  120. }
  121. _append(str, queue = false) {
  122. this._maybeAddParen(str);
  123. this._maybeIndent(str);
  124. if (queue) this._buf.queue(str);else this._buf.append(str);
  125. this._endsWithWord = false;
  126. this._endsWithInteger = false;
  127. }
  128. _maybeIndent(str) {
  129. if (this._indent && this.endsWith("\n") && str[0] !== "\n") {
  130. this._buf.queue(this._getIndent());
  131. }
  132. }
  133. _maybeAddParen(str) {
  134. const parenPushNewlineState = this._parenPushNewlineState;
  135. if (!parenPushNewlineState) return;
  136. this._parenPushNewlineState = null;
  137. let i;
  138. for (i = 0; i < str.length && str[i] === " "; i++) continue;
  139. if (i === str.length) return;
  140. const cha = str[i];
  141. if (cha !== "\n") {
  142. if (cha !== "/") return;
  143. if (i + 1 === str.length) return;
  144. const chaPost = str[i + 1];
  145. if (chaPost !== "/" && chaPost !== "*") return;
  146. }
  147. this.token("(");
  148. this.indent();
  149. parenPushNewlineState.printed = true;
  150. }
  151. _catchUp(prop, loc) {
  152. if (!this.format.retainLines) return;
  153. const pos = loc ? loc[prop] : null;
  154. if (pos && pos.line !== null) {
  155. const count = pos.line - this._buf.getCurrentLine();
  156. for (let i = 0; i < count; i++) {
  157. this._newline();
  158. }
  159. }
  160. }
  161. _getIndent() {
  162. return (0, _repeat.default)(this.format.indent.style, this._indent);
  163. }
  164. startTerminatorless(isLabel = false) {
  165. if (isLabel) {
  166. this._noLineTerminator = true;
  167. return null;
  168. } else {
  169. return this._parenPushNewlineState = {
  170. printed: false
  171. };
  172. }
  173. }
  174. endTerminatorless(state) {
  175. this._noLineTerminator = false;
  176. if (state && state.printed) {
  177. this.dedent();
  178. this.newline();
  179. this.token(")");
  180. }
  181. }
  182. print(node, parent) {
  183. if (!node) return;
  184. const oldConcise = this.format.concise;
  185. if (node._compact) {
  186. this.format.concise = true;
  187. }
  188. const printMethod = this[node.type];
  189. if (!printMethod) {
  190. throw new ReferenceError(`unknown node of type ${JSON.stringify(node.type)} with constructor ${JSON.stringify(node && node.constructor.name)}`);
  191. }
  192. this._printStack.push(node);
  193. const oldInAux = this._insideAux;
  194. this._insideAux = !node.loc;
  195. this._maybeAddAuxComment(this._insideAux && !oldInAux);
  196. let needsParens = n.needsParens(node, parent, this._printStack);
  197. if (this.format.retainFunctionParens && node.type === "FunctionExpression" && node.extra && node.extra.parenthesized) {
  198. needsParens = true;
  199. }
  200. if (needsParens) this.token("(");
  201. this._printLeadingComments(node);
  202. const loc = t.isProgram(node) || t.isFile(node) ? null : node.loc;
  203. this.withSource("start", loc, () => {
  204. printMethod.call(this, node, parent);
  205. });
  206. this._printTrailingComments(node);
  207. if (needsParens) this.token(")");
  208. this._printStack.pop();
  209. this.format.concise = oldConcise;
  210. this._insideAux = oldInAux;
  211. }
  212. _maybeAddAuxComment(enteredPositionlessNode) {
  213. if (enteredPositionlessNode) this._printAuxBeforeComment();
  214. if (!this._insideAux) this._printAuxAfterComment();
  215. }
  216. _printAuxBeforeComment() {
  217. if (this._printAuxAfterOnNextUserNode) return;
  218. this._printAuxAfterOnNextUserNode = true;
  219. const comment = this.format.auxiliaryCommentBefore;
  220. if (comment) {
  221. this._printComment({
  222. type: "CommentBlock",
  223. value: comment
  224. });
  225. }
  226. }
  227. _printAuxAfterComment() {
  228. if (!this._printAuxAfterOnNextUserNode) return;
  229. this._printAuxAfterOnNextUserNode = false;
  230. const comment = this.format.auxiliaryCommentAfter;
  231. if (comment) {
  232. this._printComment({
  233. type: "CommentBlock",
  234. value: comment
  235. });
  236. }
  237. }
  238. getPossibleRaw(node) {
  239. const extra = node.extra;
  240. if (extra && extra.raw != null && extra.rawValue != null && node.value === extra.rawValue) {
  241. return extra.raw;
  242. }
  243. }
  244. printJoin(nodes, parent, opts = {}) {
  245. if (!nodes || !nodes.length) return;
  246. if (opts.indent) this.indent();
  247. const newlineOpts = {
  248. addNewlines: opts.addNewlines
  249. };
  250. for (let i = 0; i < nodes.length; i++) {
  251. const node = nodes[i];
  252. if (!node) continue;
  253. if (opts.statement) this._printNewline(true, node, parent, newlineOpts);
  254. this.print(node, parent);
  255. if (opts.iterator) {
  256. opts.iterator(node, i);
  257. }
  258. if (opts.separator && i < nodes.length - 1) {
  259. opts.separator.call(this);
  260. }
  261. if (opts.statement) this._printNewline(false, node, parent, newlineOpts);
  262. }
  263. if (opts.indent) this.dedent();
  264. }
  265. printAndIndentOnComments(node, parent) {
  266. const indent = node.leadingComments && node.leadingComments.length > 0;
  267. if (indent) this.indent();
  268. this.print(node, parent);
  269. if (indent) this.dedent();
  270. }
  271. printBlock(parent) {
  272. const node = parent.body;
  273. if (!t.isEmptyStatement(node)) {
  274. this.space();
  275. }
  276. this.print(node, parent);
  277. }
  278. _printTrailingComments(node) {
  279. this._printComments(this._getComments(false, node));
  280. }
  281. _printLeadingComments(node) {
  282. this._printComments(this._getComments(true, node));
  283. }
  284. printInnerComments(node, indent = true) {
  285. if (!node.innerComments || !node.innerComments.length) return;
  286. if (indent) this.indent();
  287. this._printComments(node.innerComments);
  288. if (indent) this.dedent();
  289. }
  290. printSequence(nodes, parent, opts = {}) {
  291. opts.statement = true;
  292. return this.printJoin(nodes, parent, opts);
  293. }
  294. printList(items, parent, opts = {}) {
  295. if (opts.separator == null) {
  296. opts.separator = commaSeparator;
  297. }
  298. return this.printJoin(items, parent, opts);
  299. }
  300. _printNewline(leading, node, parent, opts) {
  301. if (this.format.retainLines || this.format.compact) return;
  302. if (this.format.concise) {
  303. this.space();
  304. return;
  305. }
  306. let lines = 0;
  307. if (this._buf.hasContent()) {
  308. if (!leading) lines++;
  309. if (opts.addNewlines) lines += opts.addNewlines(leading, node) || 0;
  310. const needs = leading ? n.needsWhitespaceBefore : n.needsWhitespaceAfter;
  311. if (needs(node, parent)) lines++;
  312. }
  313. this.newline(lines);
  314. }
  315. _getComments(leading, node) {
  316. return node && (leading ? node.leadingComments : node.trailingComments) || [];
  317. }
  318. _printComment(comment) {
  319. if (!this.format.shouldPrintComment(comment.value)) return;
  320. if (comment.ignore) return;
  321. if (this._printedComments.has(comment)) return;
  322. this._printedComments.add(comment);
  323. if (comment.start != null) {
  324. if (this._printedCommentStarts[comment.start]) return;
  325. this._printedCommentStarts[comment.start] = true;
  326. }
  327. const isBlockComment = comment.type === "CommentBlock";
  328. this.newline(this._buf.hasContent() && !this._noLineTerminator && isBlockComment ? 1 : 0);
  329. if (!this.endsWith("[") && !this.endsWith("{")) this.space();
  330. let val = !isBlockComment && !this._noLineTerminator ? `//${comment.value}\n` : `/*${comment.value}*/`;
  331. if (isBlockComment && this.format.indent.adjustMultilineComment) {
  332. const offset = comment.loc && comment.loc.start.column;
  333. if (offset) {
  334. const newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
  335. val = val.replace(newlineRegex, "\n");
  336. }
  337. const indentSize = Math.max(this._getIndent().length, this._buf.getCurrentColumn());
  338. val = val.replace(/\n(?!$)/g, `\n${(0, _repeat.default)(" ", indentSize)}`);
  339. }
  340. if (this.endsWith("/")) this._space();
  341. this.withSource("start", comment.loc, () => {
  342. this._append(val);
  343. });
  344. this.newline(isBlockComment && !this._noLineTerminator ? 1 : 0);
  345. }
  346. _printComments(comments) {
  347. if (!comments || !comments.length) return;
  348. for (const comment of comments) {
  349. this._printComment(comment);
  350. }
  351. }
  352. }
  353. exports.default = Printer;
  354. Object.assign(Printer.prototype, generatorFunctions);
  355. function commaSeparator() {
  356. this.token(",");
  357. this.space();
  358. }