stringifyCollection.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. 'use strict';
  2. var identity = require('../nodes/identity.js');
  3. var stringify = require('./stringify.js');
  4. var stringifyComment = require('./stringifyComment.js');
  5. function stringifyCollection(collection, ctx, options) {
  6. const flow = ctx.inFlow ?? collection.flow;
  7. const stringify = flow ? stringifyFlowCollection : stringifyBlockCollection;
  8. return stringify(collection, ctx, options);
  9. }
  10. function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
  11. const { indent, options: { commentString } } = ctx;
  12. const itemCtx = Object.assign({}, ctx, { indent: itemIndent, type: null });
  13. let chompKeep = false; // flag for the preceding node's status
  14. const lines = [];
  15. for (let i = 0; i < items.length; ++i) {
  16. const item = items[i];
  17. let comment = null;
  18. if (identity.isNode(item)) {
  19. if (!chompKeep && item.spaceBefore)
  20. lines.push('');
  21. addCommentBefore(ctx, lines, item.commentBefore, chompKeep);
  22. if (item.comment)
  23. comment = item.comment;
  24. }
  25. else if (identity.isPair(item)) {
  26. const ik = identity.isNode(item.key) ? item.key : null;
  27. if (ik) {
  28. if (!chompKeep && ik.spaceBefore)
  29. lines.push('');
  30. addCommentBefore(ctx, lines, ik.commentBefore, chompKeep);
  31. }
  32. }
  33. chompKeep = false;
  34. let str = stringify.stringify(item, itemCtx, () => (comment = null), () => (chompKeep = true));
  35. if (comment)
  36. str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
  37. if (chompKeep && comment)
  38. chompKeep = false;
  39. lines.push(blockItemPrefix + str);
  40. }
  41. let str;
  42. if (lines.length === 0) {
  43. str = flowChars.start + flowChars.end;
  44. }
  45. else {
  46. str = lines[0];
  47. for (let i = 1; i < lines.length; ++i) {
  48. const line = lines[i];
  49. str += line ? `\n${indent}${line}` : '\n';
  50. }
  51. }
  52. if (comment) {
  53. str += '\n' + stringifyComment.indentComment(commentString(comment), indent);
  54. if (onComment)
  55. onComment();
  56. }
  57. else if (chompKeep && onChompKeep)
  58. onChompKeep();
  59. return str;
  60. }
  61. function stringifyFlowCollection({ items }, ctx, { flowChars, itemIndent }) {
  62. const { indent, indentStep, flowCollectionPadding: fcPadding, options: { commentString } } = ctx;
  63. itemIndent += indentStep;
  64. const itemCtx = Object.assign({}, ctx, {
  65. indent: itemIndent,
  66. inFlow: true,
  67. type: null
  68. });
  69. let reqNewline = false;
  70. let linesAtValue = 0;
  71. const lines = [];
  72. for (let i = 0; i < items.length; ++i) {
  73. const item = items[i];
  74. let comment = null;
  75. if (identity.isNode(item)) {
  76. if (item.spaceBefore)
  77. lines.push('');
  78. addCommentBefore(ctx, lines, item.commentBefore, false);
  79. if (item.comment)
  80. comment = item.comment;
  81. }
  82. else if (identity.isPair(item)) {
  83. const ik = identity.isNode(item.key) ? item.key : null;
  84. if (ik) {
  85. if (ik.spaceBefore)
  86. lines.push('');
  87. addCommentBefore(ctx, lines, ik.commentBefore, false);
  88. if (ik.comment)
  89. reqNewline = true;
  90. }
  91. const iv = identity.isNode(item.value) ? item.value : null;
  92. if (iv) {
  93. if (iv.comment)
  94. comment = iv.comment;
  95. if (iv.commentBefore)
  96. reqNewline = true;
  97. }
  98. else if (item.value == null && ik?.comment) {
  99. comment = ik.comment;
  100. }
  101. }
  102. if (comment)
  103. reqNewline = true;
  104. let str = stringify.stringify(item, itemCtx, () => (comment = null));
  105. if (i < items.length - 1)
  106. str += ',';
  107. if (comment)
  108. str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
  109. if (!reqNewline && (lines.length > linesAtValue || str.includes('\n')))
  110. reqNewline = true;
  111. lines.push(str);
  112. linesAtValue = lines.length;
  113. }
  114. const { start, end } = flowChars;
  115. if (lines.length === 0) {
  116. return start + end;
  117. }
  118. else {
  119. if (!reqNewline) {
  120. const len = lines.reduce((sum, line) => sum + line.length + 2, 2);
  121. reqNewline = ctx.options.lineWidth > 0 && len > ctx.options.lineWidth;
  122. }
  123. if (reqNewline) {
  124. let str = start;
  125. for (const line of lines)
  126. str += line ? `\n${indentStep}${indent}${line}` : '\n';
  127. return `${str}\n${indent}${end}`;
  128. }
  129. else {
  130. return `${start}${fcPadding}${lines.join(' ')}${fcPadding}${end}`;
  131. }
  132. }
  133. }
  134. function addCommentBefore({ indent, options: { commentString } }, lines, comment, chompKeep) {
  135. if (comment && chompKeep)
  136. comment = comment.replace(/^\n+/, '');
  137. if (comment) {
  138. const ic = stringifyComment.indentComment(commentString(comment), indent);
  139. lines.push(ic.trimStart()); // Avoid double indent on first line
  140. }
  141. }
  142. exports.stringifyCollection = stringifyCollection;