@effected/yaml 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/Yaml.js +414 -0
- package/YamlDiagnostic.js +126 -0
- package/YamlDocument.js +181 -0
- package/YamlEdit.js +45 -0
- package/YamlFormat.js +309 -0
- package/YamlNode.js +396 -0
- package/YamlVisitor.js +172 -0
- package/index.d.ts +1331 -0
- package/index.js +9 -0
- package/internal/composer/anchors.js +97 -0
- package/internal/composer/block.js +1155 -0
- package/internal/composer/document.js +677 -0
- package/internal/composer/flow.js +400 -0
- package/internal/composer/scalars.js +885 -0
- package/internal/composer/state.js +117 -0
- package/internal/composer/tags.js +88 -0
- package/internal/cst-parser.js +716 -0
- package/internal/diagnostics.js +80 -0
- package/internal/diff.js +56 -0
- package/internal/fold.js +153 -0
- package/internal/lexer.js +959 -0
- package/internal/stringifier.js +797 -0
- package/package.json +47 -0
- package/tsdoc-metadata.json +11 -0
|
@@ -0,0 +1,959 @@
|
|
|
1
|
+
//#region src/internal/lexer.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a new YAML scanner for the given source text.
|
|
4
|
+
*
|
|
5
|
+
* Returns a stateful, pull-based scanner. Call {@link YamlScanner.scan} to
|
|
6
|
+
* advance to the next token, then use `getToken*` methods to inspect it.
|
|
7
|
+
*/
|
|
8
|
+
function createScanner(text) {
|
|
9
|
+
let pos = 0;
|
|
10
|
+
let line = 0;
|
|
11
|
+
let col = 0;
|
|
12
|
+
/**
|
|
13
|
+
* The indentation level of the current line. Set to `col` when we encounter
|
|
14
|
+
* the first non-whitespace character after a newline (or at start of input).
|
|
15
|
+
*/
|
|
16
|
+
let lineIndent = 0;
|
|
17
|
+
/** Whether `lineIndent` has been locked (set) for the current line. */
|
|
18
|
+
let lineIndentLocked = false;
|
|
19
|
+
/** Flow nesting depth (positive means we are inside flow context). */
|
|
20
|
+
let flowDepth = 0;
|
|
21
|
+
/** Whether we've emitted block-map-start / block-seq-start for the current indent. */
|
|
22
|
+
const blockStarted = /* @__PURE__ */ new Map();
|
|
23
|
+
/** Set when the block scalar scanner produces an empty value (contentIndent === 0). */
|
|
24
|
+
let afterEmptyBlockScalar = false;
|
|
25
|
+
/** Set when the previous token was a quoted scalar (single or double quoted). */
|
|
26
|
+
let afterQuotedScalar = false;
|
|
27
|
+
let afterFlowCollectionEnd = false;
|
|
28
|
+
/** Buffer of tokens to emit before scanning the next real token. */
|
|
29
|
+
const pending = [];
|
|
30
|
+
/** Mutable holder for the most recently produced token, set by the public {@link scan} method. */
|
|
31
|
+
const state = { currentToken: null };
|
|
32
|
+
function peek(offset = 0) {
|
|
33
|
+
const idx = pos + offset;
|
|
34
|
+
return idx < text.length ? text[idx] ?? "" : "";
|
|
35
|
+
}
|
|
36
|
+
function charAt(i) {
|
|
37
|
+
return i < text.length ? text[i] ?? "" : "";
|
|
38
|
+
}
|
|
39
|
+
function advance(count = 1) {
|
|
40
|
+
for (let i = 0; i < count; i++) if (pos < text.length) {
|
|
41
|
+
if (text[pos] === "\n") {
|
|
42
|
+
line++;
|
|
43
|
+
col = 0;
|
|
44
|
+
lineIndentLocked = false;
|
|
45
|
+
} else col++;
|
|
46
|
+
pos++;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Lock the line indent to the current column (called on first non-ws char). */
|
|
50
|
+
function lockLineIndent() {
|
|
51
|
+
if (!lineIndentLocked) {
|
|
52
|
+
lineIndent = col;
|
|
53
|
+
lineIndentLocked = true;
|
|
54
|
+
for (const key of blockStarted.keys()) if (key > lineIndent) blockStarted.delete(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function makeToken(kind, value, offset, tokenLine, tokenCol, rawLength) {
|
|
58
|
+
return {
|
|
59
|
+
kind,
|
|
60
|
+
value,
|
|
61
|
+
offset,
|
|
62
|
+
length: rawLength ?? value.length,
|
|
63
|
+
line: tokenLine,
|
|
64
|
+
column: tokenCol
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function isWhitespace(ch) {
|
|
68
|
+
return ch === " " || ch === " ";
|
|
69
|
+
}
|
|
70
|
+
function isNewline(ch) {
|
|
71
|
+
return ch === "\n" || ch === "\r";
|
|
72
|
+
}
|
|
73
|
+
function isFlowIndicator(ch) {
|
|
74
|
+
return ch === "{" || ch === "}" || ch === "[" || ch === "]" || ch === ",";
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if the current position starts a document marker (--- or ...)
|
|
78
|
+
* followed by whitespace, newline, or EOF. Used inside quoted scalars
|
|
79
|
+
* to detect unterminated strings broken by document boundaries.
|
|
80
|
+
*/
|
|
81
|
+
function isDocumentMarkerAhead() {
|
|
82
|
+
const c0 = peek();
|
|
83
|
+
const c1 = peek(1);
|
|
84
|
+
const c2 = peek(2);
|
|
85
|
+
const c3 = peek(3);
|
|
86
|
+
if (c0 === "-" && c1 === "-" && c2 === "-" || c0 === "." && c1 === "." && c2 === ".") return c3 === "" || c3 === " " || c3 === " " || c3 === "\n" || c3 === "\r";
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns true if `ch` cannot appear in a plain scalar at the current position.
|
|
91
|
+
*/
|
|
92
|
+
function isPlainScalarBreak(ch) {
|
|
93
|
+
if (ch === "" || isNewline(ch)) return true;
|
|
94
|
+
if (flowDepth > 0 && isFlowIndicator(ch)) return true;
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
function ensureBlockMap(indent, offset, tokLine, _tokCol) {
|
|
98
|
+
if (flowDepth > 0) return;
|
|
99
|
+
const started = blockStarted.get(indent);
|
|
100
|
+
if (started === "map") return;
|
|
101
|
+
if (started === "seq") return;
|
|
102
|
+
blockStarted.set(indent, "map");
|
|
103
|
+
pending.push(makeToken("block-map-start", "", offset, tokLine, indent));
|
|
104
|
+
}
|
|
105
|
+
function ensureBlockSeq(indent, offset, tokLine, _tokCol) {
|
|
106
|
+
if (flowDepth > 0) return;
|
|
107
|
+
if (blockStarted.get(indent) === "seq") return;
|
|
108
|
+
blockStarted.set(indent, "seq");
|
|
109
|
+
pending.push(makeToken("block-seq-start", "", offset, tokLine, indent));
|
|
110
|
+
}
|
|
111
|
+
function scanNewline() {
|
|
112
|
+
const start = pos;
|
|
113
|
+
const sLine = line;
|
|
114
|
+
const sCol = col;
|
|
115
|
+
if (peek() === "\r" && peek(1) === "\n") {
|
|
116
|
+
advance(2);
|
|
117
|
+
return makeToken("newline", "\r\n", start, sLine, sCol);
|
|
118
|
+
}
|
|
119
|
+
const ch = peek();
|
|
120
|
+
advance();
|
|
121
|
+
return makeToken("newline", ch, start, sLine, sCol);
|
|
122
|
+
}
|
|
123
|
+
function scanWhitespace() {
|
|
124
|
+
const start = pos;
|
|
125
|
+
const sLine = line;
|
|
126
|
+
const sCol = col;
|
|
127
|
+
if (!lineIndentLocked && peek() === " ") {
|
|
128
|
+
if (flowDepth === 0) {
|
|
129
|
+
let lookPos = pos;
|
|
130
|
+
while (lookPos < text.length && (text[lookPos] === " " || text[lookPos] === " ")) lookPos++;
|
|
131
|
+
const nextCh = lookPos < text.length ? text[lookPos] : void 0;
|
|
132
|
+
if (!afterEmptyBlockScalar && (nextCh === void 0 || nextCh === "\n" || nextCh === "\r")) {
|
|
133
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
134
|
+
return makeToken("whitespace", text.slice(start, pos), start, sLine, sCol);
|
|
135
|
+
}
|
|
136
|
+
if (nextCh === "{" || nextCh === "[") {
|
|
137
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
138
|
+
return makeToken("whitespace", text.slice(start, pos), start, sLine, sCol);
|
|
139
|
+
}
|
|
140
|
+
if (blockStarted.size === 0) {
|
|
141
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
142
|
+
return makeToken("whitespace", text.slice(start, pos), start, sLine, sCol);
|
|
143
|
+
}
|
|
144
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
145
|
+
return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
146
|
+
}
|
|
147
|
+
{
|
|
148
|
+
let lookPos = pos;
|
|
149
|
+
while (lookPos < text.length && (text[lookPos] === " " || text[lookPos] === " ")) lookPos++;
|
|
150
|
+
const nextCh = lookPos < text.length ? text[lookPos] : "";
|
|
151
|
+
if (nextCh === "]" || nextCh === "}" || nextCh === "\n" || nextCh === "\r" || nextCh === "") {
|
|
152
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
153
|
+
return makeToken("whitespace", text.slice(start, pos), start, sLine, sCol);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
157
|
+
return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
158
|
+
}
|
|
159
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
160
|
+
if (!lineIndentLocked && flowDepth === 0 && sCol === 0) {
|
|
161
|
+
const ws = text.slice(start, pos);
|
|
162
|
+
const tabIdx = ws.indexOf(" ");
|
|
163
|
+
if (tabIdx > 0) {
|
|
164
|
+
const nextCh = pos < text.length ? text[pos] : void 0;
|
|
165
|
+
if (nextCh !== void 0 && nextCh !== "\n" && nextCh !== "\r") {
|
|
166
|
+
if (blockStarted.has(tabIdx)) return makeToken("error", ws, start, sLine, sCol);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return makeToken("whitespace", text.slice(start, pos), start, sLine, sCol);
|
|
171
|
+
}
|
|
172
|
+
function scanComment() {
|
|
173
|
+
lockLineIndent();
|
|
174
|
+
const start = pos;
|
|
175
|
+
const sLine = line;
|
|
176
|
+
const sCol = col;
|
|
177
|
+
while (pos < text.length && !isNewline(peek())) advance();
|
|
178
|
+
return makeToken("comment", text.slice(start, pos), start, sLine, sCol);
|
|
179
|
+
}
|
|
180
|
+
function scanDocumentStartOrEnd() {
|
|
181
|
+
lockLineIndent();
|
|
182
|
+
const start = pos;
|
|
183
|
+
const sLine = line;
|
|
184
|
+
const sCol = col;
|
|
185
|
+
const marker = text.slice(pos, pos + 3);
|
|
186
|
+
const after = charAt(pos + 3);
|
|
187
|
+
if (after !== "" && !isNewline(after) && !isWhitespace(after)) return null;
|
|
188
|
+
advance(3);
|
|
189
|
+
const kind = marker === "---" ? "document-start" : "document-end";
|
|
190
|
+
blockStarted.clear();
|
|
191
|
+
return makeToken(kind, marker, start, sLine, sCol);
|
|
192
|
+
}
|
|
193
|
+
function scanPlainScalar() {
|
|
194
|
+
lockLineIndent();
|
|
195
|
+
const start = pos;
|
|
196
|
+
const sLine = line;
|
|
197
|
+
const sCol = col;
|
|
198
|
+
while (pos < text.length) {
|
|
199
|
+
const ch = peek();
|
|
200
|
+
if (isPlainScalarBreak(ch)) break;
|
|
201
|
+
if (ch === ":" && (isWhitespace(peek(1)) || isNewline(peek(1)) || peek(1) === "" || flowDepth > 0 && isFlowIndicator(peek(1)))) break;
|
|
202
|
+
if (ch === " " && peek(1) === "#") break;
|
|
203
|
+
if (ch === " " && peek(1) === "#") break;
|
|
204
|
+
advance();
|
|
205
|
+
}
|
|
206
|
+
let end = pos;
|
|
207
|
+
while (end > start && isWhitespace(text[end - 1] ?? "")) end--;
|
|
208
|
+
return makeToken("scalar", text.slice(start, end), start, sLine, sCol);
|
|
209
|
+
}
|
|
210
|
+
function scanSingleQuotedScalar() {
|
|
211
|
+
lockLineIndent();
|
|
212
|
+
const start = pos;
|
|
213
|
+
const sLine = line;
|
|
214
|
+
const sCol = col;
|
|
215
|
+
advance();
|
|
216
|
+
let value = "";
|
|
217
|
+
while (pos < text.length) {
|
|
218
|
+
const ch = peek();
|
|
219
|
+
if (ch === "'") if (peek(1) === "'") {
|
|
220
|
+
value += "'";
|
|
221
|
+
advance(2);
|
|
222
|
+
} else {
|
|
223
|
+
advance();
|
|
224
|
+
return makeToken("scalar", value, start, sLine, sCol, pos - start);
|
|
225
|
+
}
|
|
226
|
+
else if (ch === "\n" || ch === "\r" && peek(1) === "\n") {
|
|
227
|
+
value += " ";
|
|
228
|
+
if (ch === "\r") advance(2);
|
|
229
|
+
else advance();
|
|
230
|
+
if (col === 0 && isDocumentMarkerAhead()) return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
231
|
+
} else {
|
|
232
|
+
value += ch;
|
|
233
|
+
advance();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
237
|
+
}
|
|
238
|
+
function scanDoubleQuotedScalar() {
|
|
239
|
+
lockLineIndent();
|
|
240
|
+
const start = pos;
|
|
241
|
+
const sLine = line;
|
|
242
|
+
const sCol = col;
|
|
243
|
+
advance();
|
|
244
|
+
let value = "";
|
|
245
|
+
while (pos < text.length) {
|
|
246
|
+
const ch = peek();
|
|
247
|
+
if (ch === "\"") {
|
|
248
|
+
advance();
|
|
249
|
+
return makeToken("scalar", value, start, sLine, sCol, pos - start);
|
|
250
|
+
}
|
|
251
|
+
if (ch === "\\") {
|
|
252
|
+
advance();
|
|
253
|
+
switch (peek()) {
|
|
254
|
+
case "\\":
|
|
255
|
+
value += "\\";
|
|
256
|
+
advance();
|
|
257
|
+
break;
|
|
258
|
+
case "\"":
|
|
259
|
+
value += "\"";
|
|
260
|
+
advance();
|
|
261
|
+
break;
|
|
262
|
+
case "/":
|
|
263
|
+
value += "/";
|
|
264
|
+
advance();
|
|
265
|
+
break;
|
|
266
|
+
case "b":
|
|
267
|
+
value += "\b";
|
|
268
|
+
advance();
|
|
269
|
+
break;
|
|
270
|
+
case "f":
|
|
271
|
+
value += "\f";
|
|
272
|
+
advance();
|
|
273
|
+
break;
|
|
274
|
+
case "n":
|
|
275
|
+
value += "\n";
|
|
276
|
+
advance();
|
|
277
|
+
break;
|
|
278
|
+
case "r":
|
|
279
|
+
value += "\r";
|
|
280
|
+
advance();
|
|
281
|
+
break;
|
|
282
|
+
case " ":
|
|
283
|
+
case "t":
|
|
284
|
+
value += " ";
|
|
285
|
+
advance();
|
|
286
|
+
break;
|
|
287
|
+
case "0":
|
|
288
|
+
value += "\0";
|
|
289
|
+
advance();
|
|
290
|
+
break;
|
|
291
|
+
case "a":
|
|
292
|
+
value += "\x07";
|
|
293
|
+
advance();
|
|
294
|
+
break;
|
|
295
|
+
case "e":
|
|
296
|
+
value += "\x1B";
|
|
297
|
+
advance();
|
|
298
|
+
break;
|
|
299
|
+
case "v":
|
|
300
|
+
value += "\v";
|
|
301
|
+
advance();
|
|
302
|
+
break;
|
|
303
|
+
case " ":
|
|
304
|
+
value += " ";
|
|
305
|
+
advance();
|
|
306
|
+
break;
|
|
307
|
+
case "N":
|
|
308
|
+
value += "
";
|
|
309
|
+
advance();
|
|
310
|
+
break;
|
|
311
|
+
case "_":
|
|
312
|
+
value += "\xA0";
|
|
313
|
+
advance();
|
|
314
|
+
break;
|
|
315
|
+
case "L":
|
|
316
|
+
value += "\u2028";
|
|
317
|
+
advance();
|
|
318
|
+
break;
|
|
319
|
+
case "P":
|
|
320
|
+
value += "\u2029";
|
|
321
|
+
advance();
|
|
322
|
+
break;
|
|
323
|
+
case "x": {
|
|
324
|
+
advance();
|
|
325
|
+
const hex = text.slice(pos, pos + 2);
|
|
326
|
+
if (hex.length === 2 && /^[\da-fA-F]{2}$/.test(hex)) {
|
|
327
|
+
value += String.fromCharCode(Number.parseInt(hex, 16));
|
|
328
|
+
advance(2);
|
|
329
|
+
} else return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
case "u": {
|
|
333
|
+
advance();
|
|
334
|
+
const hex = text.slice(pos, pos + 4);
|
|
335
|
+
if (hex.length === 4 && /^[\da-fA-F]{4}$/.test(hex)) {
|
|
336
|
+
value += String.fromCodePoint(Number.parseInt(hex, 16));
|
|
337
|
+
advance(4);
|
|
338
|
+
} else return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
case "U": {
|
|
342
|
+
advance();
|
|
343
|
+
const hex = text.slice(pos, pos + 8);
|
|
344
|
+
const cp = hex.length === 8 && /^[\da-fA-F]{8}$/.test(hex) ? Number.parseInt(hex, 16) : NaN;
|
|
345
|
+
if (cp <= 1114111) {
|
|
346
|
+
value += String.fromCodePoint(cp);
|
|
347
|
+
advance(8);
|
|
348
|
+
} else return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
case "\n":
|
|
352
|
+
advance();
|
|
353
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
354
|
+
break;
|
|
355
|
+
case "\r":
|
|
356
|
+
advance();
|
|
357
|
+
if (peek() === "\n") advance();
|
|
358
|
+
while (pos < text.length && isWhitespace(peek())) advance();
|
|
359
|
+
break;
|
|
360
|
+
default: return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
361
|
+
}
|
|
362
|
+
} else if (ch === "\n" || ch === "\r" && peek(1) === "\n") {
|
|
363
|
+
value += " ";
|
|
364
|
+
if (ch === "\r") advance(2);
|
|
365
|
+
else advance();
|
|
366
|
+
if (col === 0 && isDocumentMarkerAhead()) return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
367
|
+
if (sCol > 0 && peek() === " ") {
|
|
368
|
+
advance();
|
|
369
|
+
return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
value += ch;
|
|
373
|
+
advance();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
377
|
+
}
|
|
378
|
+
function scanBlockScalar() {
|
|
379
|
+
lockLineIndent();
|
|
380
|
+
const start = pos;
|
|
381
|
+
const sLine = line;
|
|
382
|
+
const sCol = col;
|
|
383
|
+
const isFolded = peek() === ">";
|
|
384
|
+
advance();
|
|
385
|
+
let chomp = "clip";
|
|
386
|
+
let explicitIndent = 0;
|
|
387
|
+
for (let hc = 0; hc < 2 && pos < text.length && !isNewline(peek()); hc++) {
|
|
388
|
+
const ch = peek();
|
|
389
|
+
if (ch === "-") {
|
|
390
|
+
chomp = "strip";
|
|
391
|
+
advance();
|
|
392
|
+
} else if (ch === "+") {
|
|
393
|
+
chomp = "keep";
|
|
394
|
+
advance();
|
|
395
|
+
} else if (ch >= "1" && ch <= "9") {
|
|
396
|
+
explicitIndent = Number.parseInt(ch, 10);
|
|
397
|
+
advance();
|
|
398
|
+
} else break;
|
|
399
|
+
}
|
|
400
|
+
let hadHeaderWhitespace = false;
|
|
401
|
+
while (pos < text.length && isWhitespace(peek())) {
|
|
402
|
+
hadHeaderWhitespace = true;
|
|
403
|
+
advance();
|
|
404
|
+
}
|
|
405
|
+
if (pos < text.length && !isNewline(peek()) && peek() !== "") if (peek() === "#" && hadHeaderWhitespace) while (pos < text.length && !isNewline(peek())) advance();
|
|
406
|
+
else {
|
|
407
|
+
while (pos < text.length && !isNewline(peek())) advance();
|
|
408
|
+
return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
409
|
+
}
|
|
410
|
+
if (pos < text.length && isNewline(peek())) if (peek() === "\r" && peek(1) === "\n") advance(2);
|
|
411
|
+
else advance();
|
|
412
|
+
let contentIndent = explicitIndent;
|
|
413
|
+
let foundContent = explicitIndent > 0;
|
|
414
|
+
if (explicitIndent > 0) {
|
|
415
|
+
let parentIndent = lineIndent;
|
|
416
|
+
let scanBack = start - 1;
|
|
417
|
+
while (scanBack >= 0 && (text[scanBack] === " " || text[scanBack] === " ")) scanBack--;
|
|
418
|
+
if (scanBack >= 0 && text[scanBack] === ":") {
|
|
419
|
+
let lineStart = scanBack;
|
|
420
|
+
while (lineStart > 0 && text[lineStart - 1] !== "\n" && text[lineStart - 1] !== "\r") lineStart--;
|
|
421
|
+
let spaces = 0;
|
|
422
|
+
while (lineStart + spaces < text.length && text[lineStart + spaces] === " ") spaces++;
|
|
423
|
+
if (lineStart + spaces < text.length && text[lineStart + spaces] === "-") {
|
|
424
|
+
const afterDash = lineStart + spaces + 1;
|
|
425
|
+
if (afterDash < text.length && (text[afterDash] === " " || text[afterDash] === " ")) parentIndent = spaces + 2;
|
|
426
|
+
else parentIndent = spaces;
|
|
427
|
+
} else parentIndent = spaces;
|
|
428
|
+
} else if (scanBack >= 0 && text[scanBack] === "-") {
|
|
429
|
+
let lineStart = scanBack;
|
|
430
|
+
while (lineStart > 0 && text[lineStart - 1] !== "\n" && text[lineStart - 1] !== "\r") lineStart--;
|
|
431
|
+
parentIndent = scanBack - lineStart;
|
|
432
|
+
} else {
|
|
433
|
+
let maxBlockIndent = 0;
|
|
434
|
+
for (const key of blockStarted.keys()) if (key > maxBlockIndent) maxBlockIndent = key;
|
|
435
|
+
parentIndent = maxBlockIndent;
|
|
436
|
+
}
|
|
437
|
+
contentIndent = parentIndent + explicitIndent;
|
|
438
|
+
foundContent = true;
|
|
439
|
+
}
|
|
440
|
+
if (contentIndent === 0) {
|
|
441
|
+
let scanAhead = pos;
|
|
442
|
+
while (scanAhead < text.length) {
|
|
443
|
+
let spaces = 0;
|
|
444
|
+
while (scanAhead < text.length && text[scanAhead] === " ") {
|
|
445
|
+
spaces++;
|
|
446
|
+
scanAhead++;
|
|
447
|
+
}
|
|
448
|
+
if (spaces === 0 && scanAhead + 2 < text.length) {
|
|
449
|
+
const sc0 = text[scanAhead];
|
|
450
|
+
const sc1 = text[scanAhead + 1];
|
|
451
|
+
const sc2 = text[scanAhead + 2];
|
|
452
|
+
const sc3 = scanAhead + 3 < text.length ? text[scanAhead + 3] : "";
|
|
453
|
+
if ((sc0 === "-" && sc1 === "-" && sc2 === "-" || sc0 === "." && sc1 === "." && sc2 === ".") && (sc3 === "" || sc3 === " " || sc3 === " " || sc3 === "\n" || sc3 === "\r")) break;
|
|
454
|
+
}
|
|
455
|
+
if (scanAhead >= text.length || text[scanAhead] === "\n" || text[scanAhead] === "\r") {
|
|
456
|
+
if (scanAhead < text.length) {
|
|
457
|
+
scanAhead++;
|
|
458
|
+
if (text[scanAhead - 1] === "\r" && scanAhead < text.length && text[scanAhead] === "\n") scanAhead++;
|
|
459
|
+
}
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
contentIndent = spaces;
|
|
463
|
+
foundContent = true;
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (!foundContent || contentIndent === 0 && blockStarted.size > 0) {
|
|
468
|
+
if (chomp === "keep") {
|
|
469
|
+
let count = 0;
|
|
470
|
+
while (pos < text.length) {
|
|
471
|
+
while (pos < text.length && (text[pos] === " " || text[pos] === " ")) {
|
|
472
|
+
pos++;
|
|
473
|
+
col++;
|
|
474
|
+
}
|
|
475
|
+
if (pos >= text.length) {
|
|
476
|
+
if (count === 0) count = 1;
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
if (text[pos] === "\n") {
|
|
480
|
+
count++;
|
|
481
|
+
pos++;
|
|
482
|
+
line++;
|
|
483
|
+
col = 0;
|
|
484
|
+
} else if (text[pos] === "\r") {
|
|
485
|
+
count++;
|
|
486
|
+
pos++;
|
|
487
|
+
if (pos < text.length && text[pos] === "\n") pos++;
|
|
488
|
+
line++;
|
|
489
|
+
col = 0;
|
|
490
|
+
} else break;
|
|
491
|
+
}
|
|
492
|
+
return makeToken("scalar", "\n".repeat(count), start, sLine, sCol, pos - start);
|
|
493
|
+
}
|
|
494
|
+
afterEmptyBlockScalar = true;
|
|
495
|
+
return makeToken("scalar", "", start, sLine, sCol, pos - start);
|
|
496
|
+
}
|
|
497
|
+
const lines = [];
|
|
498
|
+
const trailingNewlines = [];
|
|
499
|
+
while (pos < text.length) {
|
|
500
|
+
let spaces = 0;
|
|
501
|
+
const lineStart = pos;
|
|
502
|
+
while (pos < text.length && text[pos] === " ") {
|
|
503
|
+
spaces++;
|
|
504
|
+
pos++;
|
|
505
|
+
col++;
|
|
506
|
+
}
|
|
507
|
+
if (spaces === 0 && pos + 2 < text.length) {
|
|
508
|
+
const c0 = text[pos];
|
|
509
|
+
const c1 = text[pos + 1];
|
|
510
|
+
const c2 = text[pos + 2];
|
|
511
|
+
const c3 = pos + 3 < text.length ? text[pos + 3] : "";
|
|
512
|
+
if ((c0 === "-" && c1 === "-" && c2 === "-" || c0 === "." && c1 === "." && c2 === ".") && (c3 === "" || c3 === " " || c3 === " " || c3 === "\n" || c3 === "\r")) {
|
|
513
|
+
pos = lineStart;
|
|
514
|
+
col = 0;
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (pos >= text.length || text[pos] === "\n" || text[pos] === "\r") {
|
|
519
|
+
if (spaces > contentIndent) {
|
|
520
|
+
for (const nl of trailingNewlines) lines.push(nl);
|
|
521
|
+
trailingNewlines.length = 0;
|
|
522
|
+
lines.push(" ".repeat(spaces - contentIndent));
|
|
523
|
+
} else trailingNewlines.push("");
|
|
524
|
+
if (pos < text.length) {
|
|
525
|
+
if (text[pos] === "\r" && pos + 1 < text.length && text[pos + 1] === "\n") pos += 2;
|
|
526
|
+
else pos++;
|
|
527
|
+
line++;
|
|
528
|
+
col = 0;
|
|
529
|
+
}
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
if (spaces < contentIndent) {
|
|
533
|
+
pos = lineStart;
|
|
534
|
+
col = 0;
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
for (const nl of trailingNewlines) lines.push(nl);
|
|
538
|
+
trailingNewlines.length = 0;
|
|
539
|
+
const extra = " ".repeat(spaces - contentIndent);
|
|
540
|
+
const contentStart = pos;
|
|
541
|
+
while (pos < text.length && text[pos] !== "\n" && text[pos] !== "\r") {
|
|
542
|
+
pos++;
|
|
543
|
+
col++;
|
|
544
|
+
}
|
|
545
|
+
lines.push(extra + text.slice(contentStart, pos));
|
|
546
|
+
if (pos < text.length) {
|
|
547
|
+
if (text[pos] === "\r" && pos + 1 < text.length && text[pos + 1] === "\n") pos += 2;
|
|
548
|
+
else pos++;
|
|
549
|
+
line++;
|
|
550
|
+
col = 0;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
let value;
|
|
554
|
+
if (isFolded) {
|
|
555
|
+
let result = "";
|
|
556
|
+
let prevMoreIndented = false;
|
|
557
|
+
let hadContent = false;
|
|
558
|
+
for (let i = 0; i < lines.length; i++) {
|
|
559
|
+
const ln = lines[i] ?? "";
|
|
560
|
+
const isMoreIndented = ln.length > 0 && (ln[0] === " " || ln[0] === " ");
|
|
561
|
+
if (ln === "") result += "\n";
|
|
562
|
+
else if (!hadContent) {
|
|
563
|
+
result += ln;
|
|
564
|
+
prevMoreIndented = isMoreIndented;
|
|
565
|
+
hadContent = true;
|
|
566
|
+
} else {
|
|
567
|
+
if (result[result.length - 1] === "\n") if (isMoreIndented || prevMoreIndented) result += `\n${ln}`;
|
|
568
|
+
else result += ln;
|
|
569
|
+
else if (isMoreIndented || prevMoreIndented) result += `\n${ln}`;
|
|
570
|
+
else result += ` ${ln}`;
|
|
571
|
+
prevMoreIndented = isMoreIndented;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (chomp === "strip") {} else if (chomp === "keep") {
|
|
575
|
+
result += "\n";
|
|
576
|
+
for (const _nl of trailingNewlines) result += "\n";
|
|
577
|
+
} else result += "\n";
|
|
578
|
+
value = result;
|
|
579
|
+
} else {
|
|
580
|
+
value = lines.join("\n");
|
|
581
|
+
if (chomp === "strip") {} else if (chomp === "keep") {
|
|
582
|
+
value += "\n";
|
|
583
|
+
for (const _nl of trailingNewlines) value += "\n";
|
|
584
|
+
} else value += "\n";
|
|
585
|
+
}
|
|
586
|
+
return makeToken("scalar", value, start, sLine, sCol, pos - start);
|
|
587
|
+
}
|
|
588
|
+
function scanAnchor() {
|
|
589
|
+
lockLineIndent();
|
|
590
|
+
const start = pos;
|
|
591
|
+
const sLine = line;
|
|
592
|
+
const sCol = col;
|
|
593
|
+
advance();
|
|
594
|
+
const nameStart = pos;
|
|
595
|
+
while (pos < text.length && !isWhitespace(peek()) && !isNewline(peek()) && !isFlowIndicator(peek())) advance();
|
|
596
|
+
const name = text.slice(nameStart, pos);
|
|
597
|
+
if (name.length === 0) return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
598
|
+
return makeToken("anchor", name, start, sLine, sCol, pos - start);
|
|
599
|
+
}
|
|
600
|
+
function scanAlias() {
|
|
601
|
+
lockLineIndent();
|
|
602
|
+
const start = pos;
|
|
603
|
+
const sLine = line;
|
|
604
|
+
const sCol = col;
|
|
605
|
+
advance();
|
|
606
|
+
const nameStart = pos;
|
|
607
|
+
while (pos < text.length && !isWhitespace(peek()) && !isNewline(peek()) && !isFlowIndicator(peek())) advance();
|
|
608
|
+
const name = text.slice(nameStart, pos);
|
|
609
|
+
if (name.length === 0) return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
610
|
+
return makeToken("alias", name, start, sLine, sCol, pos - start);
|
|
611
|
+
}
|
|
612
|
+
function scanTag() {
|
|
613
|
+
lockLineIndent();
|
|
614
|
+
const start = pos;
|
|
615
|
+
const sLine = line;
|
|
616
|
+
const sCol = col;
|
|
617
|
+
advance();
|
|
618
|
+
if (peek() === "<") {
|
|
619
|
+
advance();
|
|
620
|
+
while (pos < text.length && peek() !== ">") {
|
|
621
|
+
if (isNewline(peek())) return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
622
|
+
advance();
|
|
623
|
+
}
|
|
624
|
+
if (peek() === ">") advance();
|
|
625
|
+
else return makeToken("error", text.slice(start, pos), start, sLine, sCol);
|
|
626
|
+
return makeToken("tag", text.slice(start, pos), start, sLine, sCol);
|
|
627
|
+
}
|
|
628
|
+
if (peek() === "!") advance();
|
|
629
|
+
while (pos < text.length && !isWhitespace(peek()) && !isNewline(peek()) && !isFlowIndicator(peek())) advance();
|
|
630
|
+
return makeToken("tag", text.slice(start, pos), start, sLine, sCol);
|
|
631
|
+
}
|
|
632
|
+
function scanDirective() {
|
|
633
|
+
lockLineIndent();
|
|
634
|
+
const start = pos;
|
|
635
|
+
const sLine = line;
|
|
636
|
+
const sCol = col;
|
|
637
|
+
while (pos < text.length && !isNewline(peek())) advance();
|
|
638
|
+
return makeToken("directive", text.slice(start, pos), start, sLine, sCol);
|
|
639
|
+
}
|
|
640
|
+
function scanNext() {
|
|
641
|
+
if (pending.length > 0) {
|
|
642
|
+
const next = pending.shift();
|
|
643
|
+
if (next !== void 0) return next;
|
|
644
|
+
}
|
|
645
|
+
if (pos >= text.length) return null;
|
|
646
|
+
const prevWasQuoted = afterQuotedScalar;
|
|
647
|
+
const prevWasFlowEnd = afterFlowCollectionEnd;
|
|
648
|
+
if (flowDepth > 0) {
|
|
649
|
+
const ch0 = peek();
|
|
650
|
+
const isComment = ch0 === "#" && (pos === 0 || col === 0 || text[pos - 1] === " " || text[pos - 1] === " " || text[pos - 1] === "\n" || text[pos - 1] === "\r");
|
|
651
|
+
if (!isWhitespace(ch0) && !isNewline(ch0) && !isComment) {
|
|
652
|
+
afterQuotedScalar = false;
|
|
653
|
+
afterFlowCollectionEnd = false;
|
|
654
|
+
}
|
|
655
|
+
} else {
|
|
656
|
+
afterQuotedScalar = false;
|
|
657
|
+
afterFlowCollectionEnd = false;
|
|
658
|
+
}
|
|
659
|
+
const ch = peek();
|
|
660
|
+
if (ch === "") {
|
|
661
|
+
const start = pos;
|
|
662
|
+
const sLine = line;
|
|
663
|
+
const sCol = col;
|
|
664
|
+
advance();
|
|
665
|
+
return makeToken("byte-order-mark", "", start, sLine, sCol);
|
|
666
|
+
}
|
|
667
|
+
if (isNewline(ch)) return scanNewline();
|
|
668
|
+
if (isWhitespace(ch)) return scanWhitespace();
|
|
669
|
+
afterEmptyBlockScalar = false;
|
|
670
|
+
if (ch === "#") {
|
|
671
|
+
if (pos === 0 || col === 0) return scanComment();
|
|
672
|
+
const prev = text[pos - 1];
|
|
673
|
+
if (prev === " " || prev === " " || prev === "\n" || prev === "\r") return scanComment();
|
|
674
|
+
if (prevWasQuoted) {
|
|
675
|
+
const start = pos;
|
|
676
|
+
const sLine = line;
|
|
677
|
+
const sCol = col;
|
|
678
|
+
advance();
|
|
679
|
+
return makeToken("error", "#", start, sLine, sCol);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (col === 0 && ch === "-" && peek(1) === "-" && peek(2) === "-") {
|
|
683
|
+
const marker = scanDocumentStartOrEnd();
|
|
684
|
+
if (marker) return marker;
|
|
685
|
+
}
|
|
686
|
+
if (col === 0 && ch === "." && peek(1) === "." && peek(2) === ".") {
|
|
687
|
+
const marker = scanDocumentStartOrEnd();
|
|
688
|
+
if (marker) return marker;
|
|
689
|
+
}
|
|
690
|
+
if (ch === "%" && col === 0 && flowDepth === 0) return scanDirective();
|
|
691
|
+
if ((ch === "|" || ch === ">") && flowDepth === 0) {
|
|
692
|
+
const next = peek(1);
|
|
693
|
+
if (next === "" || isNewline(next) || isWhitespace(next) || next === "-" || next === "+" || next >= "0" && next <= "9" || next === "#") return scanBlockScalar();
|
|
694
|
+
}
|
|
695
|
+
if (ch === "{") {
|
|
696
|
+
lockLineIndent();
|
|
697
|
+
const start = pos;
|
|
698
|
+
const sLine = line;
|
|
699
|
+
const sCol = col;
|
|
700
|
+
advance();
|
|
701
|
+
flowDepth++;
|
|
702
|
+
return makeToken("flow-map-start", "{", start, sLine, sCol);
|
|
703
|
+
}
|
|
704
|
+
if (ch === "}") {
|
|
705
|
+
lockLineIndent();
|
|
706
|
+
const start = pos;
|
|
707
|
+
const sLine = line;
|
|
708
|
+
const sCol = col;
|
|
709
|
+
advance();
|
|
710
|
+
if (flowDepth > 0) flowDepth--;
|
|
711
|
+
afterFlowCollectionEnd = true;
|
|
712
|
+
return makeToken("flow-map-end", "}", start, sLine, sCol);
|
|
713
|
+
}
|
|
714
|
+
if (ch === "[") {
|
|
715
|
+
lockLineIndent();
|
|
716
|
+
const start = pos;
|
|
717
|
+
const sLine = line;
|
|
718
|
+
const sCol = col;
|
|
719
|
+
advance();
|
|
720
|
+
flowDepth++;
|
|
721
|
+
return makeToken("flow-seq-start", "[", start, sLine, sCol);
|
|
722
|
+
}
|
|
723
|
+
if (ch === "]") {
|
|
724
|
+
lockLineIndent();
|
|
725
|
+
const start = pos;
|
|
726
|
+
const sLine = line;
|
|
727
|
+
const sCol = col;
|
|
728
|
+
advance();
|
|
729
|
+
if (flowDepth > 0) flowDepth--;
|
|
730
|
+
afterFlowCollectionEnd = true;
|
|
731
|
+
return makeToken("flow-seq-end", "]", start, sLine, sCol);
|
|
732
|
+
}
|
|
733
|
+
if (ch === ",") {
|
|
734
|
+
lockLineIndent();
|
|
735
|
+
const start = pos;
|
|
736
|
+
const sLine = line;
|
|
737
|
+
const sCol = col;
|
|
738
|
+
advance();
|
|
739
|
+
if (flowDepth === 0) return makeToken("error", ",", start, sLine, sCol);
|
|
740
|
+
return makeToken("flow-separator", ",", start, sLine, sCol);
|
|
741
|
+
}
|
|
742
|
+
if (ch === "&") return scanAnchor();
|
|
743
|
+
if (ch === "*") return scanAlias();
|
|
744
|
+
if (ch === "!") return scanTag();
|
|
745
|
+
if (ch === "?" && (isWhitespace(peek(1)) || isNewline(peek(1)) || peek(1) === "")) {
|
|
746
|
+
lockLineIndent();
|
|
747
|
+
const indent = lineIndent;
|
|
748
|
+
const start = pos;
|
|
749
|
+
const sLine = line;
|
|
750
|
+
const sCol = col;
|
|
751
|
+
advance();
|
|
752
|
+
if (flowDepth === 0) {
|
|
753
|
+
let lk = pos;
|
|
754
|
+
let hasTab = false;
|
|
755
|
+
let firstTabPos = -1;
|
|
756
|
+
while (lk < text.length && (text[lk] === " " || text[lk] === " ")) {
|
|
757
|
+
if (text[lk] === " " && !hasTab) {
|
|
758
|
+
hasTab = true;
|
|
759
|
+
firstTabPos = lk;
|
|
760
|
+
}
|
|
761
|
+
lk++;
|
|
762
|
+
}
|
|
763
|
+
if (hasTab && lk < text.length && text[lk] !== "\n" && text[lk] !== "\r") {
|
|
764
|
+
while (pos < firstTabPos) advance();
|
|
765
|
+
const tabStart = pos;
|
|
766
|
+
const tabLine = line;
|
|
767
|
+
const tabCol = col;
|
|
768
|
+
advance();
|
|
769
|
+
ensureBlockMap(indent, start, sLine, sCol);
|
|
770
|
+
pending.push(makeToken("block-map-key", "?", start, sLine, sCol));
|
|
771
|
+
pending.push(makeToken("error", " ", tabStart, tabLine, tabCol));
|
|
772
|
+
const first = pending.shift();
|
|
773
|
+
if (first !== void 0) return first;
|
|
774
|
+
return makeToken("block-map-key", "?", start, sLine, sCol);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
ensureBlockMap(indent, start, sLine, sCol);
|
|
778
|
+
if (pending.length > 0) {
|
|
779
|
+
pending.push(makeToken("block-map-key", "?", start, sLine, sCol));
|
|
780
|
+
const first = pending.shift();
|
|
781
|
+
if (first !== void 0) return first;
|
|
782
|
+
}
|
|
783
|
+
return makeToken("block-map-key", "?", start, sLine, sCol);
|
|
784
|
+
}
|
|
785
|
+
if (ch === "-" && (isWhitespace(peek(1)) || isNewline(peek(1)) || peek(1) === "") && flowDepth === 0) {
|
|
786
|
+
lockLineIndent();
|
|
787
|
+
const indent = lineIndent;
|
|
788
|
+
const start = pos;
|
|
789
|
+
const sLine = line;
|
|
790
|
+
const sCol = col;
|
|
791
|
+
advance();
|
|
792
|
+
{
|
|
793
|
+
let lk = pos;
|
|
794
|
+
let hasTab = false;
|
|
795
|
+
let firstTabPos = -1;
|
|
796
|
+
while (lk < text.length && (text[lk] === " " || text[lk] === " ")) {
|
|
797
|
+
if (text[lk] === " " && !hasTab) {
|
|
798
|
+
hasTab = true;
|
|
799
|
+
firstTabPos = lk;
|
|
800
|
+
}
|
|
801
|
+
lk++;
|
|
802
|
+
}
|
|
803
|
+
if (hasTab && lk < text.length) {
|
|
804
|
+
const nc = text[lk];
|
|
805
|
+
const afterNc = lk + 1 < text.length ? text[lk + 1] : "";
|
|
806
|
+
if (nc === "-" && (afterNc === " " || afterNc === " " || afterNc === "\n" || afterNc === "\r" || afterNc === "") || nc === "?" && (afterNc === " " || afterNc === " " || afterNc === "\n" || afterNc === "\r" || afterNc === "")) {
|
|
807
|
+
while (pos < firstTabPos) advance();
|
|
808
|
+
const tabStart = pos;
|
|
809
|
+
const tabLine = line;
|
|
810
|
+
const tabCol = col;
|
|
811
|
+
advance();
|
|
812
|
+
ensureBlockSeq(indent, start, sLine, sCol);
|
|
813
|
+
pending.push(makeToken("block-seq-entry", "-", start, sLine, sCol));
|
|
814
|
+
pending.push(makeToken("error", " ", tabStart, tabLine, tabCol));
|
|
815
|
+
const first = pending.shift();
|
|
816
|
+
if (first !== void 0) return first;
|
|
817
|
+
return makeToken("block-seq-entry", "-", start, sLine, sCol);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
ensureBlockSeq(indent, start, sLine, sCol);
|
|
822
|
+
if (pending.length > 0) {
|
|
823
|
+
pending.push(makeToken("block-seq-entry", "-", start, sLine, sCol));
|
|
824
|
+
const first = pending.shift();
|
|
825
|
+
if (first !== void 0) return first;
|
|
826
|
+
}
|
|
827
|
+
return makeToken("block-seq-entry", "-", start, sLine, sCol);
|
|
828
|
+
}
|
|
829
|
+
if (ch === ":" && (isWhitespace(peek(1)) || isNewline(peek(1)) || peek(1) === "" || flowDepth > 0 && isFlowIndicator(peek(1)) || flowDepth > 0 && prevWasQuoted || flowDepth > 0 && prevWasFlowEnd)) {
|
|
830
|
+
lockLineIndent();
|
|
831
|
+
const indent = lineIndent;
|
|
832
|
+
const start = pos;
|
|
833
|
+
const sLine = line;
|
|
834
|
+
const sCol = col;
|
|
835
|
+
advance();
|
|
836
|
+
if (flowDepth === 0) {
|
|
837
|
+
let lk = pos;
|
|
838
|
+
let hasTab = false;
|
|
839
|
+
let firstTabPos = -1;
|
|
840
|
+
while (lk < text.length && (text[lk] === " " || text[lk] === " ")) {
|
|
841
|
+
if (text[lk] === " " && !hasTab) {
|
|
842
|
+
hasTab = true;
|
|
843
|
+
firstTabPos = lk;
|
|
844
|
+
}
|
|
845
|
+
lk++;
|
|
846
|
+
}
|
|
847
|
+
if (hasTab && lk < text.length) {
|
|
848
|
+
const nc = text[lk];
|
|
849
|
+
const afterNc = lk + 1 < text.length ? text[lk + 1] : "";
|
|
850
|
+
if (nc === "-" && (afterNc === " " || afterNc === " " || afterNc === "\n" || afterNc === "\r" || afterNc === "") || nc === "?" && (afterNc === " " || afterNc === " " || afterNc === "\n" || afterNc === "\r" || afterNc === "")) {
|
|
851
|
+
while (pos < firstTabPos) advance();
|
|
852
|
+
const tabStart = pos;
|
|
853
|
+
const tabLine = line;
|
|
854
|
+
const tabCol = col;
|
|
855
|
+
advance();
|
|
856
|
+
ensureBlockMap(indent, start, sLine, sCol);
|
|
857
|
+
pending.push(makeToken("block-map-value", ":", start, sLine, sCol));
|
|
858
|
+
pending.push(makeToken("error", " ", tabStart, tabLine, tabCol));
|
|
859
|
+
const first = pending.shift();
|
|
860
|
+
if (first !== void 0) return first;
|
|
861
|
+
return makeToken("block-map-value", ":", start, sLine, sCol);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
ensureBlockMap(indent, start, sLine, sCol);
|
|
866
|
+
if (pending.length > 0) {
|
|
867
|
+
pending.push(makeToken("block-map-value", ":", start, sLine, sCol));
|
|
868
|
+
const first = pending.shift();
|
|
869
|
+
if (first !== void 0) return first;
|
|
870
|
+
}
|
|
871
|
+
return makeToken("block-map-value", ":", start, sLine, sCol);
|
|
872
|
+
}
|
|
873
|
+
if (ch === "'") {
|
|
874
|
+
afterQuotedScalar = true;
|
|
875
|
+
return scanSingleQuotedScalar();
|
|
876
|
+
}
|
|
877
|
+
if (ch === "\"") {
|
|
878
|
+
afterQuotedScalar = true;
|
|
879
|
+
return scanDoubleQuotedScalar();
|
|
880
|
+
}
|
|
881
|
+
afterQuotedScalar = false;
|
|
882
|
+
return scanPlainScalar();
|
|
883
|
+
}
|
|
884
|
+
return {
|
|
885
|
+
scan() {
|
|
886
|
+
const token = scanNext();
|
|
887
|
+
state.currentToken = token;
|
|
888
|
+
return token === null ? null : token.kind;
|
|
889
|
+
},
|
|
890
|
+
getToken() {
|
|
891
|
+
return state.currentToken === null ? null : state.currentToken.kind;
|
|
892
|
+
},
|
|
893
|
+
getTokenValue() {
|
|
894
|
+
return state.currentToken === null ? "" : state.currentToken.value;
|
|
895
|
+
},
|
|
896
|
+
getTokenOffset() {
|
|
897
|
+
return state.currentToken === null ? 0 : state.currentToken.offset;
|
|
898
|
+
},
|
|
899
|
+
getTokenLength() {
|
|
900
|
+
return state.currentToken === null ? 0 : state.currentToken.length;
|
|
901
|
+
},
|
|
902
|
+
getTokenLine() {
|
|
903
|
+
return state.currentToken === null ? 0 : state.currentToken.line;
|
|
904
|
+
},
|
|
905
|
+
getTokenColumn() {
|
|
906
|
+
return state.currentToken === null ? 0 : state.currentToken.column;
|
|
907
|
+
},
|
|
908
|
+
getPosition() {
|
|
909
|
+
return pos;
|
|
910
|
+
},
|
|
911
|
+
setPosition(newPos) {
|
|
912
|
+
pos = 0;
|
|
913
|
+
line = 0;
|
|
914
|
+
col = 0;
|
|
915
|
+
while (pos < newPos && pos < text.length) {
|
|
916
|
+
if (text[pos] === "\n") {
|
|
917
|
+
line++;
|
|
918
|
+
col = 0;
|
|
919
|
+
} else col++;
|
|
920
|
+
pos++;
|
|
921
|
+
}
|
|
922
|
+
lineIndent = 0;
|
|
923
|
+
lineIndentLocked = false;
|
|
924
|
+
flowDepth = 0;
|
|
925
|
+
blockStarted.clear();
|
|
926
|
+
pending.length = 0;
|
|
927
|
+
afterEmptyBlockScalar = false;
|
|
928
|
+
afterQuotedScalar = false;
|
|
929
|
+
afterFlowCollectionEnd = false;
|
|
930
|
+
state.currentToken = null;
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Tokenize a YAML source string into an array of {@link YamlToken} records.
|
|
936
|
+
*
|
|
937
|
+
* Lexer errors are embedded as `"error"` tokens in the result; the downstream
|
|
938
|
+
* parser/composer collects them and records diagnostics as needed.
|
|
939
|
+
*/
|
|
940
|
+
function lexAll(text) {
|
|
941
|
+
const scanner = createScanner(text);
|
|
942
|
+
const tokens = [];
|
|
943
|
+
let kind = scanner.scan();
|
|
944
|
+
while (kind !== null) {
|
|
945
|
+
tokens.push({
|
|
946
|
+
kind,
|
|
947
|
+
value: scanner.getTokenValue(),
|
|
948
|
+
offset: scanner.getTokenOffset(),
|
|
949
|
+
length: scanner.getTokenLength(),
|
|
950
|
+
line: scanner.getTokenLine(),
|
|
951
|
+
column: scanner.getTokenColumn()
|
|
952
|
+
});
|
|
953
|
+
kind = scanner.scan();
|
|
954
|
+
}
|
|
955
|
+
return tokens;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
//#endregion
|
|
959
|
+
export { createScanner, lexAll };
|