test-events.js
  1  'use strict';
  2  
  3  var parseCst = require('./parse-cst.js');
  4  var Document = require('./Document-9b4560a1.js');
  5  require('./PlainValue-ec8e588e.js');
  6  require('./resolveSeq-d03cb037.js');
  7  require('./Schema-88e323a7.js');
  8  require('./warnings-1000a372.js');
  9  
 10  function testEvents(src, options) {
 11    const opt = Object.assign({
 12      keepCstNodes: true,
 13      keepNodeTypes: true,
 14      version: '1.2'
 15    }, options);
 16    const docs = parseCst.parse(src).map(cstDoc => new Document.Document(opt).parse(cstDoc));
 17    const errDoc = docs.find(doc => doc.errors.length > 0);
 18    const error = errDoc ? errDoc.errors[0].message : null;
 19    const events = ['+STR'];
 20  
 21    try {
 22      for (let i = 0; i < docs.length; ++i) {
 23        const doc = docs[i];
 24        let root = doc.contents;
 25        if (Array.isArray(root)) root = root[0];
 26        const [rootStart, rootEnd] = doc.range || [0, 0];
 27        let e = doc.errors[0] && doc.errors[0].source;
 28        if (e && e.type === 'SEQ_ITEM') e = e.node;
 29        if (e && (e.type === 'DOCUMENT' || e.range.start < rootStart)) throw new Error();
 30        let docStart = '+DOC';
 31        const pre = src.slice(0, rootStart);
 32        const explicitDoc = /---\s*$/.test(pre);
 33        if (explicitDoc) docStart += ' ---';else if (!doc.contents) continue;
 34        events.push(docStart);
 35        addEvents(events, doc, e, root);
 36        if (doc.contents && doc.contents.length > 1) throw new Error();
 37        let docEnd = '-DOC';
 38  
 39        if (rootEnd) {
 40          const post = src.slice(rootEnd);
 41          if (/^\.\.\./.test(post)) docEnd += ' ...';
 42        }
 43  
 44        events.push(docEnd);
 45      }
 46    } catch (e) {
 47      return {
 48        events,
 49        error: error || e
 50      };
 51    }
 52  
 53    events.push('-STR');
 54    return {
 55      events,
 56      error
 57    };
 58  }
 59  
 60  function addEvents(events, doc, e, node) {
 61    if (!node) {
 62      events.push('=VAL :');
 63      return;
 64    }
 65  
 66    if (e && node.cstNode === e) throw new Error();
 67    let props = '';
 68    let anchor = doc.anchors.getName(node);
 69  
 70    if (anchor) {
 71      if (/\d$/.test(anchor)) {
 72        const alt = anchor.replace(/\d$/, '');
 73        if (doc.anchors.getNode(alt)) anchor = alt;
 74      }
 75  
 76      props = ` &${anchor}`;
 77    }
 78  
 79    if (node.cstNode && node.cstNode.tag) {
 80      const {
 81        handle,
 82        suffix
 83      } = node.cstNode.tag;
 84      props += handle === '!' && !suffix ? ' <!>' : ` <${node.tag}>`;
 85    }
 86  
 87    let scalar = null;
 88  
 89    switch (node.type) {
 90      case 'ALIAS':
 91        {
 92          let alias = doc.anchors.getName(node.source);
 93  
 94          if (/\d$/.test(alias)) {
 95            const alt = alias.replace(/\d$/, '');
 96            if (doc.anchors.getNode(alt)) alias = alt;
 97          }
 98  
 99          events.push(`=ALI${props} *${alias}`);
100        }
101        break;
102  
103      case 'BLOCK_FOLDED':
104        scalar = '>';
105        break;
106  
107      case 'BLOCK_LITERAL':
108        scalar = '|';
109        break;
110  
111      case 'PLAIN':
112        scalar = ':';
113        break;
114  
115      case 'QUOTE_DOUBLE':
116        scalar = '"';
117        break;
118  
119      case 'QUOTE_SINGLE':
120        scalar = "'";
121        break;
122  
123      case 'PAIR':
124        events.push(`+MAP${props}`);
125        addEvents(events, doc, e, node.key);
126        addEvents(events, doc, e, node.value);
127        events.push('-MAP');
128        break;
129  
130      case 'FLOW_SEQ':
131      case 'SEQ':
132        events.push(`+SEQ${props}`);
133        node.items.forEach(item => {
134          addEvents(events, doc, e, item);
135        });
136        events.push('-SEQ');
137        break;
138  
139      case 'FLOW_MAP':
140      case 'MAP':
141        events.push(`+MAP${props}`);
142        node.items.forEach(({
143          key,
144          value
145        }) => {
146          addEvents(events, doc, e, key);
147          addEvents(events, doc, e, value);
148        });
149        events.push('-MAP');
150        break;
151  
152      default:
153        throw new Error(`Unexpected node type ${node.type}`);
154    }
155  
156    if (scalar) {
157      const value = node.cstNode.strValue.replace(/\\/g, '\\\\').replace(/\0/g, '\\0').replace(/\x07/g, '\\a').replace(/\x08/g, '\\b').replace(/\t/g, '\\t').replace(/\n/g, '\\n').replace(/\v/g, '\\v').replace(/\f/g, '\\f').replace(/\r/g, '\\r').replace(/\x1b/g, '\\e');
158      events.push(`=VAL${props} ${scalar}${value}`);
159    }
160  }
161  
162  exports.testEvents = testEvents;