UNPKG

5.59 kBJavaScriptView Raw
1'use strict';
2
3function 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 // At the doc level, tabs at line start may be parsed
35 // as leading white space rather than indentation.
36 // In a flow collection, only the parser handles indent.
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 // Could here handle preceding comments differently
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 // else fallthrough
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
150exports.resolveProps = resolveProps;