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