stringifyDocument.js 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { isNode } from '../nodes/identity.js';
  2. import { createStringifyContext, stringify } from './stringify.js';
  3. import { indentComment, lineComment } from './stringifyComment.js';
  4. function stringifyDocument(doc, options) {
  5. const lines = [];
  6. let hasDirectives = options.directives === true;
  7. if (options.directives !== false && doc.directives) {
  8. const dir = doc.directives.toString(doc);
  9. if (dir) {
  10. lines.push(dir);
  11. hasDirectives = true;
  12. }
  13. else if (doc.directives.docStart)
  14. hasDirectives = true;
  15. }
  16. if (hasDirectives)
  17. lines.push('---');
  18. const ctx = createStringifyContext(doc, options);
  19. const { commentString } = ctx.options;
  20. if (doc.commentBefore) {
  21. if (lines.length !== 1)
  22. lines.unshift('');
  23. const cs = commentString(doc.commentBefore);
  24. lines.unshift(indentComment(cs, ''));
  25. }
  26. let chompKeep = false;
  27. let contentComment = null;
  28. if (doc.contents) {
  29. if (isNode(doc.contents)) {
  30. if (doc.contents.spaceBefore && hasDirectives)
  31. lines.push('');
  32. if (doc.contents.commentBefore) {
  33. const cs = commentString(doc.contents.commentBefore);
  34. lines.push(indentComment(cs, ''));
  35. }
  36. // top-level block scalars need to be indented if followed by a comment
  37. ctx.forceBlockIndent = !!doc.comment;
  38. contentComment = doc.contents.comment;
  39. }
  40. const onChompKeep = contentComment ? undefined : () => (chompKeep = true);
  41. let body = stringify(doc.contents, ctx, () => (contentComment = null), onChompKeep);
  42. if (contentComment)
  43. body += lineComment(body, '', commentString(contentComment));
  44. if ((body[0] === '|' || body[0] === '>') &&
  45. lines[lines.length - 1] === '---') {
  46. // Top-level block scalars with a preceding doc marker ought to use the
  47. // same line for their header.
  48. lines[lines.length - 1] = `--- ${body}`;
  49. }
  50. else
  51. lines.push(body);
  52. }
  53. else {
  54. lines.push(stringify(doc.contents, ctx));
  55. }
  56. if (doc.directives?.docEnd) {
  57. if (doc.comment) {
  58. const cs = commentString(doc.comment);
  59. if (cs.includes('\n')) {
  60. lines.push('...');
  61. lines.push(indentComment(cs, ''));
  62. }
  63. else {
  64. lines.push(`... ${cs}`);
  65. }
  66. }
  67. else {
  68. lines.push('...');
  69. }
  70. }
  71. else {
  72. let dc = doc.comment;
  73. if (dc && chompKeep)
  74. dc = dc.replace(/^\n+/, '');
  75. if (dc) {
  76. if ((!chompKeep || contentComment) && lines[lines.length - 1] !== '')
  77. lines.push('');
  78. lines.push(indentComment(commentString(dc), ''));
  79. }
  80. }
  81. return lines.join('\n') + '\n';
  82. }
  83. export { stringifyDocument };