stringify.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. 'use strict';
  2. var anchors = require('../doc/anchors.js');
  3. var identity = require('../nodes/identity.js');
  4. var stringifyComment = require('./stringifyComment.js');
  5. var stringifyString = require('./stringifyString.js');
  6. function createStringifyContext(doc, options) {
  7. const opt = Object.assign({
  8. blockQuote: true,
  9. commentString: stringifyComment.stringifyComment,
  10. defaultKeyType: null,
  11. defaultStringType: 'PLAIN',
  12. directives: null,
  13. doubleQuotedAsJSON: false,
  14. doubleQuotedMinMultiLineLength: 40,
  15. falseStr: 'false',
  16. flowCollectionPadding: true,
  17. indentSeq: true,
  18. lineWidth: 80,
  19. minContentWidth: 20,
  20. nullStr: 'null',
  21. simpleKeys: false,
  22. singleQuote: null,
  23. trueStr: 'true',
  24. verifyAliasOrder: true
  25. }, doc.schema.toStringOptions, options);
  26. let inFlow;
  27. switch (opt.collectionStyle) {
  28. case 'block':
  29. inFlow = false;
  30. break;
  31. case 'flow':
  32. inFlow = true;
  33. break;
  34. default:
  35. inFlow = null;
  36. }
  37. return {
  38. anchors: new Set(),
  39. doc,
  40. flowCollectionPadding: opt.flowCollectionPadding ? ' ' : '',
  41. indent: '',
  42. indentStep: typeof opt.indent === 'number' ? ' '.repeat(opt.indent) : ' ',
  43. inFlow,
  44. options: opt
  45. };
  46. }
  47. function getTagObject(tags, item) {
  48. if (item.tag) {
  49. const match = tags.filter(t => t.tag === item.tag);
  50. if (match.length > 0)
  51. return match.find(t => t.format === item.format) ?? match[0];
  52. }
  53. let tagObj = undefined;
  54. let obj;
  55. if (identity.isScalar(item)) {
  56. obj = item.value;
  57. const match = tags.filter(t => t.identify?.(obj));
  58. tagObj =
  59. match.find(t => t.format === item.format) ?? match.find(t => !t.format);
  60. }
  61. else {
  62. obj = item;
  63. tagObj = tags.find(t => t.nodeClass && obj instanceof t.nodeClass);
  64. }
  65. if (!tagObj) {
  66. const name = obj?.constructor?.name ?? typeof obj;
  67. throw new Error(`Tag not resolved for ${name} value`);
  68. }
  69. return tagObj;
  70. }
  71. // needs to be called before value stringifier to allow for circular anchor refs
  72. function stringifyProps(node, tagObj, { anchors: anchors$1, doc }) {
  73. if (!doc.directives)
  74. return '';
  75. const props = [];
  76. const anchor = (identity.isScalar(node) || identity.isCollection(node)) && node.anchor;
  77. if (anchor && anchors.anchorIsValid(anchor)) {
  78. anchors$1.add(anchor);
  79. props.push(`&${anchor}`);
  80. }
  81. const tag = node.tag ? node.tag : tagObj.default ? null : tagObj.tag;
  82. if (tag)
  83. props.push(doc.directives.tagString(tag));
  84. return props.join(' ');
  85. }
  86. function stringify(item, ctx, onComment, onChompKeep) {
  87. if (identity.isPair(item))
  88. return item.toString(ctx, onComment, onChompKeep);
  89. if (identity.isAlias(item)) {
  90. if (ctx.doc.directives)
  91. return item.toString(ctx);
  92. if (ctx.resolvedAliases?.has(item)) {
  93. throw new TypeError(`Cannot stringify circular structure without alias nodes`);
  94. }
  95. else {
  96. if (ctx.resolvedAliases)
  97. ctx.resolvedAliases.add(item);
  98. else
  99. ctx.resolvedAliases = new Set([item]);
  100. item = item.resolve(ctx.doc);
  101. }
  102. }
  103. let tagObj = undefined;
  104. const node = identity.isNode(item)
  105. ? item
  106. : ctx.doc.createNode(item, { onTagObj: o => (tagObj = o) });
  107. if (!tagObj)
  108. tagObj = getTagObject(ctx.doc.schema.tags, node);
  109. const props = stringifyProps(node, tagObj, ctx);
  110. if (props.length > 0)
  111. ctx.indentAtStart = (ctx.indentAtStart ?? 0) + props.length + 1;
  112. const str = typeof tagObj.stringify === 'function'
  113. ? tagObj.stringify(node, ctx, onComment, onChompKeep)
  114. : identity.isScalar(node)
  115. ? stringifyString.stringifyString(node, ctx, onComment, onChompKeep)
  116. : node.toString(ctx, onComment, onChompKeep);
  117. if (!props)
  118. return str;
  119. return identity.isScalar(node) || str[0] === '{' || str[0] === '['
  120. ? `${props} ${str}`
  121. : `${props}\n${ctx.indent}${str}`;
  122. }
  123. exports.createStringifyContext = createStringifyContext;
  124. exports.stringify = stringify;