test-events.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. 'use strict';
  2. var identity = require('./nodes/identity.js');
  3. var publicApi = require('./public-api.js');
  4. var visit = require('./visit.js');
  5. const scalarChar = {
  6. BLOCK_FOLDED: '>',
  7. BLOCK_LITERAL: '|',
  8. PLAIN: ':',
  9. QUOTE_DOUBLE: '"',
  10. QUOTE_SINGLE: "'"
  11. };
  12. function anchorExists(doc, anchor) {
  13. let found = false;
  14. visit.visit(doc, {
  15. Value(_key, node) {
  16. if (node.anchor === anchor) {
  17. found = true;
  18. return visit.visit.BREAK;
  19. }
  20. }
  21. });
  22. return found;
  23. }
  24. // test harness for yaml-test-suite event tests
  25. function testEvents(src) {
  26. const docs = publicApi.parseAllDocuments(src);
  27. const errDoc = docs.find(doc => doc.errors.length > 0);
  28. const error = errDoc ? errDoc.errors[0].message : null;
  29. const events = ['+STR'];
  30. try {
  31. for (let i = 0; i < docs.length; ++i) {
  32. const doc = docs[i];
  33. let root = doc.contents;
  34. if (Array.isArray(root))
  35. root = root[0];
  36. const [rootStart] = doc.range || [0];
  37. const error = doc.errors[0];
  38. if (error && (!error.pos || error.pos[0] < rootStart))
  39. throw new Error();
  40. let docStart = '+DOC';
  41. if (doc.directives.docStart)
  42. docStart += ' ---';
  43. else if (doc.contents &&
  44. doc.contents.range[2] === doc.contents.range[0] &&
  45. !doc.contents.anchor &&
  46. !doc.contents.tag)
  47. continue;
  48. events.push(docStart);
  49. addEvents(events, doc, error?.pos[0] ?? -1, root);
  50. let docEnd = '-DOC';
  51. if (doc.directives.docEnd)
  52. docEnd += ' ...';
  53. events.push(docEnd);
  54. }
  55. }
  56. catch (e) {
  57. return { events, error: error ?? e };
  58. }
  59. events.push('-STR');
  60. return { events, error };
  61. }
  62. function addEvents(events, doc, errPos, node) {
  63. if (!node) {
  64. events.push('=VAL :');
  65. return;
  66. }
  67. if (errPos !== -1 && identity.isNode(node) && node.range[0] >= errPos)
  68. throw new Error();
  69. let props = '';
  70. let anchor = identity.isScalar(node) || identity.isCollection(node) ? node.anchor : undefined;
  71. if (anchor) {
  72. if (/\d$/.test(anchor)) {
  73. const alt = anchor.replace(/\d$/, '');
  74. if (anchorExists(doc, alt))
  75. anchor = alt;
  76. }
  77. props = ` &${anchor}`;
  78. }
  79. if (identity.isNode(node) && node.tag)
  80. props += ` <${node.tag}>`;
  81. if (identity.isMap(node)) {
  82. const ev = node.flow ? '+MAP {}' : '+MAP';
  83. events.push(`${ev}${props}`);
  84. node.items.forEach(({ key, value }) => {
  85. addEvents(events, doc, errPos, key);
  86. addEvents(events, doc, errPos, value);
  87. });
  88. events.push('-MAP');
  89. }
  90. else if (identity.isSeq(node)) {
  91. const ev = node.flow ? '+SEQ []' : '+SEQ';
  92. events.push(`${ev}${props}`);
  93. node.items.forEach(item => {
  94. addEvents(events, doc, errPos, item);
  95. });
  96. events.push('-SEQ');
  97. }
  98. else if (identity.isPair(node)) {
  99. events.push(`+MAP${props}`);
  100. addEvents(events, doc, errPos, node.key);
  101. addEvents(events, doc, errPos, node.value);
  102. events.push('-MAP');
  103. }
  104. else if (identity.isAlias(node)) {
  105. let alias = node.source;
  106. if (alias && /\d$/.test(alias)) {
  107. const alt = alias.replace(/\d$/, '');
  108. if (anchorExists(doc, alt))
  109. alias = alt;
  110. }
  111. events.push(`=ALI${props} *${alias}`);
  112. }
  113. else {
  114. const scalar = scalarChar[String(node.type)];
  115. if (!scalar)
  116. throw new Error(`Unexpected node type ${node.type}`);
  117. const value = node.source
  118. .replace(/\\/g, '\\\\')
  119. .replace(/\0/g, '\\0')
  120. .replace(/\x07/g, '\\a')
  121. .replace(/\x08/g, '\\b')
  122. .replace(/\t/g, '\\t')
  123. .replace(/\n/g, '\\n')
  124. .replace(/\v/g, '\\v')
  125. .replace(/\f/g, '\\f')
  126. .replace(/\r/g, '\\r')
  127. .replace(/\x1b/g, '\\e');
  128. events.push(`=VAL${props} ${scalar}${value}`);
  129. }
  130. }
  131. exports.testEvents = testEvents;