1 | 'use strict';
|
2 |
|
3 | function resolveProps(tokens, { flow, indicator, next, offset, onError, parentIndent, startOnNewline }) {
|
4 | let spaceBefore = false;
|
5 | let atNewline = startOnNewline;
|
6 | let hasSpace = startOnNewline;
|
7 | let comment = '';
|
8 | let commentSep = '';
|
9 | let hasNewline = false;
|
10 | let reqSpace = false;
|
11 | let tab = null;
|
12 | let anchor = null;
|
13 | let tag = null;
|
14 | let newlineAfterProp = null;
|
15 | let comma = null;
|
16 | let found = null;
|
17 | let start = null;
|
18 | for (const token of tokens) {
|
19 | if (reqSpace) {
|
20 | if (token.type !== 'space' &&
|
21 | token.type !== 'newline' &&
|
22 | token.type !== 'comma')
|
23 | onError(token.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
|
24 | reqSpace = false;
|
25 | }
|
26 | if (tab) {
|
27 | if (atNewline && token.type !== 'comment' && token.type !== 'newline') {
|
28 | onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
|
29 | }
|
30 | tab = null;
|
31 | }
|
32 | switch (token.type) {
|
33 | case 'space':
|
34 |
|
35 |
|
36 |
|
37 | if (!flow &&
|
38 | (indicator !== 'doc-start' || next?.type !== 'flow-collection') &&
|
39 | token.source.includes('\t')) {
|
40 | tab = token;
|
41 | }
|
42 | hasSpace = true;
|
43 | break;
|
44 | case 'comment': {
|
45 | if (!hasSpace)
|
46 | onError(token, 'MISSING_CHAR', 'Comments must be separated from other tokens by white space characters');
|
47 | const cb = token.source.substring(1) || ' ';
|
48 | if (!comment)
|
49 | comment = cb;
|
50 | else
|
51 | comment += commentSep + cb;
|
52 | commentSep = '';
|
53 | atNewline = false;
|
54 | break;
|
55 | }
|
56 | case 'newline':
|
57 | if (atNewline) {
|
58 | if (comment)
|
59 | comment += token.source;
|
60 | else
|
61 | spaceBefore = true;
|
62 | }
|
63 | else
|
64 | commentSep += token.source;
|
65 | atNewline = true;
|
66 | hasNewline = true;
|
67 | if (anchor || tag)
|
68 | newlineAfterProp = token;
|
69 | hasSpace = true;
|
70 | break;
|
71 | case 'anchor':
|
72 | if (anchor)
|
73 | onError(token, 'MULTIPLE_ANCHORS', 'A node can have at most one anchor');
|
74 | if (token.source.endsWith(':'))
|
75 | onError(token.offset + token.source.length - 1, 'BAD_ALIAS', 'Anchor ending in : is ambiguous', true);
|
76 | anchor = token;
|
77 | if (start === null)
|
78 | start = token.offset;
|
79 | atNewline = false;
|
80 | hasSpace = false;
|
81 | reqSpace = true;
|
82 | break;
|
83 | case 'tag': {
|
84 | if (tag)
|
85 | onError(token, 'MULTIPLE_TAGS', 'A node can have at most one tag');
|
86 | tag = token;
|
87 | if (start === null)
|
88 | start = token.offset;
|
89 | atNewline = false;
|
90 | hasSpace = false;
|
91 | reqSpace = true;
|
92 | break;
|
93 | }
|
94 | case indicator:
|
95 |
|
96 | if (anchor || tag)
|
97 | onError(token, 'BAD_PROP_ORDER', `Anchors and tags must be after the ${token.source} indicator`);
|
98 | if (found)
|
99 | onError(token, 'UNEXPECTED_TOKEN', `Unexpected ${token.source} in ${flow ?? 'collection'}`);
|
100 | found = token;
|
101 | atNewline =
|
102 | indicator === 'seq-item-ind' || indicator === 'explicit-key-ind';
|
103 | hasSpace = false;
|
104 | break;
|
105 | case 'comma':
|
106 | if (flow) {
|
107 | if (comma)
|
108 | onError(token, 'UNEXPECTED_TOKEN', `Unexpected , in ${flow}`);
|
109 | comma = token;
|
110 | atNewline = false;
|
111 | hasSpace = false;
|
112 | break;
|
113 | }
|
114 |
|
115 | default:
|
116 | onError(token, 'UNEXPECTED_TOKEN', `Unexpected ${token.type} token`);
|
117 | atNewline = false;
|
118 | hasSpace = false;
|
119 | }
|
120 | }
|
121 | const last = tokens[tokens.length - 1];
|
122 | const end = last ? last.offset + last.source.length : offset;
|
123 | if (reqSpace &&
|
124 | next &&
|
125 | next.type !== 'space' &&
|
126 | next.type !== 'newline' &&
|
127 | next.type !== 'comma' &&
|
128 | (next.type !== 'scalar' || next.source !== '')) {
|
129 | onError(next.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
|
130 | }
|
131 | if (tab &&
|
132 | ((atNewline && tab.indent <= parentIndent) ||
|
133 | next?.type === 'block-map' ||
|
134 | next?.type === 'block-seq'))
|
135 | onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
|
136 | return {
|
137 | comma,
|
138 | found,
|
139 | spaceBefore,
|
140 | comment,
|
141 | hasNewline,
|
142 | anchor,
|
143 | tag,
|
144 | newlineAfterProp,
|
145 | end,
|
146 | start: start ?? end
|
147 | };
|
148 | }
|
149 |
|
150 | exports.resolveProps = resolveProps;
|