Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80698 views
1
'use strict';
2
3
/*eslint-disable max-len,no-use-before-define*/
4
5
var common = require('./common');
6
var YAMLException = require('./exception');
7
var Mark = require('./mark');
8
var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe');
9
var DEFAULT_FULL_SCHEMA = require('./schema/default_full');
10
11
12
var _hasOwnProperty = Object.prototype.hasOwnProperty;
13
14
15
var CONTEXT_FLOW_IN = 1;
16
var CONTEXT_FLOW_OUT = 2;
17
var CONTEXT_BLOCK_IN = 3;
18
var CONTEXT_BLOCK_OUT = 4;
19
20
21
var CHOMPING_CLIP = 1;
22
var CHOMPING_STRIP = 2;
23
var CHOMPING_KEEP = 3;
24
25
26
var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/;
27
var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/;
28
var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/;
29
var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i;
30
var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;
31
32
33
function is_EOL(c) {
34
return (c === 0x0A/* LF */) || (c === 0x0D/* CR */);
35
}
36
37
function is_WHITE_SPACE(c) {
38
return (c === 0x09/* Tab */) || (c === 0x20/* Space */);
39
}
40
41
function is_WS_OR_EOL(c) {
42
return (c === 0x09/* Tab */) ||
43
(c === 0x20/* Space */) ||
44
(c === 0x0A/* LF */) ||
45
(c === 0x0D/* CR */);
46
}
47
48
function is_FLOW_INDICATOR(c) {
49
return 0x2C/* , */ === c ||
50
0x5B/* [ */ === c ||
51
0x5D/* ] */ === c ||
52
0x7B/* { */ === c ||
53
0x7D/* } */ === c;
54
}
55
56
function fromHexCode(c) {
57
var lc;
58
59
if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) {
60
return c - 0x30;
61
}
62
63
/*eslint-disable no-bitwise*/
64
lc = c | 0x20;
65
66
if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) {
67
return lc - 0x61 + 10;
68
}
69
70
return -1;
71
}
72
73
function escapedHexLen(c) {
74
if (c === 0x78/* x */) { return 2; }
75
if (c === 0x75/* u */) { return 4; }
76
if (c === 0x55/* U */) { return 8; }
77
return 0;
78
}
79
80
function fromDecimalCode(c) {
81
if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) {
82
return c - 0x30;
83
}
84
85
return -1;
86
}
87
88
function simpleEscapeSequence(c) {
89
return (c === 0x30/* 0 */) ? '\x00' :
90
(c === 0x61/* a */) ? '\x07' :
91
(c === 0x62/* b */) ? '\x08' :
92
(c === 0x74/* t */) ? '\x09' :
93
(c === 0x09/* Tab */) ? '\x09' :
94
(c === 0x6E/* n */) ? '\x0A' :
95
(c === 0x76/* v */) ? '\x0B' :
96
(c === 0x66/* f */) ? '\x0C' :
97
(c === 0x72/* r */) ? '\x0D' :
98
(c === 0x65/* e */) ? '\x1B' :
99
(c === 0x20/* Space */) ? ' ' :
100
(c === 0x22/* " */) ? '\x22' :
101
(c === 0x2F/* / */) ? '/' :
102
(c === 0x5C/* \ */) ? '\x5C' :
103
(c === 0x4E/* N */) ? '\x85' :
104
(c === 0x5F/* _ */) ? '\xA0' :
105
(c === 0x4C/* L */) ? '\u2028' :
106
(c === 0x50/* P */) ? '\u2029' : '';
107
}
108
109
function charFromCodepoint(c) {
110
if (c <= 0xFFFF) {
111
return String.fromCharCode(c);
112
}
113
// Encode UTF-16 surrogate pair
114
// https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF
115
return String.fromCharCode(((c - 0x010000) >> 10) + 0xD800,
116
((c - 0x010000) & 0x03FF) + 0xDC00);
117
}
118
119
var simpleEscapeCheck = new Array(256); // integer, for fast access
120
var simpleEscapeMap = new Array(256);
121
for (var i = 0; i < 256; i++) {
122
simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0;
123
simpleEscapeMap[i] = simpleEscapeSequence(i);
124
}
125
126
127
function State(input, options) {
128
this.input = input;
129
130
this.filename = options['filename'] || null;
131
this.schema = options['schema'] || DEFAULT_FULL_SCHEMA;
132
this.onWarning = options['onWarning'] || null;
133
this.legacy = options['legacy'] || false;
134
135
this.implicitTypes = this.schema.compiledImplicit;
136
this.typeMap = this.schema.compiledTypeMap;
137
138
this.length = input.length;
139
this.position = 0;
140
this.line = 0;
141
this.lineStart = 0;
142
this.lineIndent = 0;
143
144
this.documents = [];
145
146
/*
147
this.version;
148
this.checkLineBreaks;
149
this.tagMap;
150
this.anchorMap;
151
this.tag;
152
this.anchor;
153
this.kind;
154
this.result;*/
155
156
}
157
158
159
function generateError(state, message) {
160
return new YAMLException(
161
message,
162
new Mark(state.filename, state.input, state.position, state.line, (state.position - state.lineStart)));
163
}
164
165
function throwError(state, message) {
166
throw generateError(state, message);
167
}
168
169
function throwWarning(state, message) {
170
var error = generateError(state, message);
171
172
if (state.onWarning) {
173
state.onWarning.call(null, error);
174
} else {
175
throw error;
176
}
177
}
178
179
180
var directiveHandlers = {
181
182
YAML: function handleYamlDirective(state, name, args) {
183
184
var match, major, minor;
185
186
if (null !== state.version) {
187
throwError(state, 'duplication of %YAML directive');
188
}
189
190
if (1 !== args.length) {
191
throwError(state, 'YAML directive accepts exactly one argument');
192
}
193
194
match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]);
195
196
if (null === match) {
197
throwError(state, 'ill-formed argument of the YAML directive');
198
}
199
200
major = parseInt(match[1], 10);
201
minor = parseInt(match[2], 10);
202
203
if (1 !== major) {
204
throwError(state, 'unacceptable YAML version of the document');
205
}
206
207
state.version = args[0];
208
state.checkLineBreaks = (minor < 2);
209
210
if (1 !== minor && 2 !== minor) {
211
throwWarning(state, 'unsupported YAML version of the document');
212
}
213
},
214
215
TAG: function handleTagDirective(state, name, args) {
216
217
var handle, prefix;
218
219
if (2 !== args.length) {
220
throwError(state, 'TAG directive accepts exactly two arguments');
221
}
222
223
handle = args[0];
224
prefix = args[1];
225
226
if (!PATTERN_TAG_HANDLE.test(handle)) {
227
throwError(state, 'ill-formed tag handle (first argument) of the TAG directive');
228
}
229
230
if (_hasOwnProperty.call(state.tagMap, handle)) {
231
throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle');
232
}
233
234
if (!PATTERN_TAG_URI.test(prefix)) {
235
throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive');
236
}
237
238
state.tagMap[handle] = prefix;
239
}
240
};
241
242
243
function captureSegment(state, start, end, checkJson) {
244
var _position, _length, _character, _result;
245
246
if (start < end) {
247
_result = state.input.slice(start, end);
248
249
if (checkJson) {
250
for (_position = 0, _length = _result.length;
251
_position < _length;
252
_position += 1) {
253
_character = _result.charCodeAt(_position);
254
if (!(0x09 === _character ||
255
0x20 <= _character && _character <= 0x10FFFF)) {
256
throwError(state, 'expected valid JSON character');
257
}
258
}
259
}
260
261
state.result += _result;
262
}
263
}
264
265
function mergeMappings(state, destination, source) {
266
var sourceKeys, key, index, quantity;
267
268
if (!common.isObject(source)) {
269
throwError(state, 'cannot merge mappings; the provided source object is unacceptable');
270
}
271
272
sourceKeys = Object.keys(source);
273
274
for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {
275
key = sourceKeys[index];
276
277
if (!_hasOwnProperty.call(destination, key)) {
278
destination[key] = source[key];
279
}
280
}
281
}
282
283
function storeMappingPair(state, _result, keyTag, keyNode, valueNode) {
284
var index, quantity;
285
286
keyNode = String(keyNode);
287
288
if (null === _result) {
289
_result = {};
290
}
291
292
if ('tag:yaml.org,2002:merge' === keyTag) {
293
if (Array.isArray(valueNode)) {
294
for (index = 0, quantity = valueNode.length; index < quantity; index += 1) {
295
mergeMappings(state, _result, valueNode[index]);
296
}
297
} else {
298
mergeMappings(state, _result, valueNode);
299
}
300
} else {
301
_result[keyNode] = valueNode;
302
}
303
304
return _result;
305
}
306
307
function readLineBreak(state) {
308
var ch;
309
310
ch = state.input.charCodeAt(state.position);
311
312
if (0x0A/* LF */ === ch) {
313
state.position++;
314
} else if (0x0D/* CR */ === ch) {
315
state.position++;
316
if (0x0A/* LF */ === state.input.charCodeAt(state.position)) {
317
state.position++;
318
}
319
} else {
320
throwError(state, 'a line break is expected');
321
}
322
323
state.line += 1;
324
state.lineStart = state.position;
325
}
326
327
function skipSeparationSpace(state, allowComments, checkIndent) {
328
var lineBreaks = 0,
329
ch = state.input.charCodeAt(state.position);
330
331
while (0 !== ch) {
332
while (is_WHITE_SPACE(ch)) {
333
ch = state.input.charCodeAt(++state.position);
334
}
335
336
if (allowComments && 0x23/* # */ === ch) {
337
do {
338
ch = state.input.charCodeAt(++state.position);
339
} while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && 0 !== ch);
340
}
341
342
if (is_EOL(ch)) {
343
readLineBreak(state);
344
345
ch = state.input.charCodeAt(state.position);
346
lineBreaks++;
347
state.lineIndent = 0;
348
349
while (0x20/* Space */ === ch) {
350
state.lineIndent++;
351
ch = state.input.charCodeAt(++state.position);
352
}
353
} else {
354
break;
355
}
356
}
357
358
if (-1 !== checkIndent && 0 !== lineBreaks && state.lineIndent < checkIndent) {
359
throwWarning(state, 'deficient indentation');
360
}
361
362
return lineBreaks;
363
}
364
365
function testDocumentSeparator(state) {
366
var _position = state.position,
367
ch;
368
369
ch = state.input.charCodeAt(_position);
370
371
// Condition state.position === state.lineStart is tested
372
// in parent on each call, for efficiency. No needs to test here again.
373
if ((0x2D/* - */ === ch || 0x2E/* . */ === ch) &&
374
state.input.charCodeAt(_position + 1) === ch &&
375
state.input.charCodeAt(_position + 2) === ch) {
376
377
_position += 3;
378
379
ch = state.input.charCodeAt(_position);
380
381
if (ch === 0 || is_WS_OR_EOL(ch)) {
382
return true;
383
}
384
}
385
386
return false;
387
}
388
389
function writeFoldedLines(state, count) {
390
if (1 === count) {
391
state.result += ' ';
392
} else if (count > 1) {
393
state.result += common.repeat('\n', count - 1);
394
}
395
}
396
397
398
function readPlainScalar(state, nodeIndent, withinFlowCollection) {
399
var preceding,
400
following,
401
captureStart,
402
captureEnd,
403
hasPendingContent,
404
_line,
405
_lineStart,
406
_lineIndent,
407
_kind = state.kind,
408
_result = state.result,
409
ch;
410
411
ch = state.input.charCodeAt(state.position);
412
413
if (is_WS_OR_EOL(ch) ||
414
is_FLOW_INDICATOR(ch) ||
415
0x23/* # */ === ch ||
416
0x26/* & */ === ch ||
417
0x2A/* * */ === ch ||
418
0x21/* ! */ === ch ||
419
0x7C/* | */ === ch ||
420
0x3E/* > */ === ch ||
421
0x27/* ' */ === ch ||
422
0x22/* " */ === ch ||
423
0x25/* % */ === ch ||
424
0x40/* @ */ === ch ||
425
0x60/* ` */ === ch) {
426
return false;
427
}
428
429
if (0x3F/* ? */ === ch || 0x2D/* - */ === ch) {
430
following = state.input.charCodeAt(state.position + 1);
431
432
if (is_WS_OR_EOL(following) ||
433
withinFlowCollection && is_FLOW_INDICATOR(following)) {
434
return false;
435
}
436
}
437
438
state.kind = 'scalar';
439
state.result = '';
440
captureStart = captureEnd = state.position;
441
hasPendingContent = false;
442
443
while (0 !== ch) {
444
if (0x3A/* : */ === ch) {
445
following = state.input.charCodeAt(state.position + 1);
446
447
if (is_WS_OR_EOL(following) ||
448
withinFlowCollection && is_FLOW_INDICATOR(following)) {
449
break;
450
}
451
452
} else if (0x23/* # */ === ch) {
453
preceding = state.input.charCodeAt(state.position - 1);
454
455
if (is_WS_OR_EOL(preceding)) {
456
break;
457
}
458
459
} else if ((state.position === state.lineStart && testDocumentSeparator(state)) ||
460
withinFlowCollection && is_FLOW_INDICATOR(ch)) {
461
break;
462
463
} else if (is_EOL(ch)) {
464
_line = state.line;
465
_lineStart = state.lineStart;
466
_lineIndent = state.lineIndent;
467
skipSeparationSpace(state, false, -1);
468
469
if (state.lineIndent >= nodeIndent) {
470
hasPendingContent = true;
471
ch = state.input.charCodeAt(state.position);
472
continue;
473
} else {
474
state.position = captureEnd;
475
state.line = _line;
476
state.lineStart = _lineStart;
477
state.lineIndent = _lineIndent;
478
break;
479
}
480
}
481
482
if (hasPendingContent) {
483
captureSegment(state, captureStart, captureEnd, false);
484
writeFoldedLines(state, state.line - _line);
485
captureStart = captureEnd = state.position;
486
hasPendingContent = false;
487
}
488
489
if (!is_WHITE_SPACE(ch)) {
490
captureEnd = state.position + 1;
491
}
492
493
ch = state.input.charCodeAt(++state.position);
494
}
495
496
captureSegment(state, captureStart, captureEnd, false);
497
498
if (state.result) {
499
return true;
500
}
501
502
state.kind = _kind;
503
state.result = _result;
504
return false;
505
}
506
507
function readSingleQuotedScalar(state, nodeIndent) {
508
var ch,
509
captureStart, captureEnd;
510
511
ch = state.input.charCodeAt(state.position);
512
513
if (0x27/* ' */ !== ch) {
514
return false;
515
}
516
517
state.kind = 'scalar';
518
state.result = '';
519
state.position++;
520
captureStart = captureEnd = state.position;
521
522
while (0 !== (ch = state.input.charCodeAt(state.position))) {
523
if (0x27/* ' */ === ch) {
524
captureSegment(state, captureStart, state.position, true);
525
ch = state.input.charCodeAt(++state.position);
526
527
if (0x27/* ' */ === ch) {
528
captureStart = captureEnd = state.position;
529
state.position++;
530
} else {
531
return true;
532
}
533
534
} else if (is_EOL(ch)) {
535
captureSegment(state, captureStart, captureEnd, true);
536
writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent));
537
captureStart = captureEnd = state.position;
538
539
} else if (state.position === state.lineStart && testDocumentSeparator(state)) {
540
throwError(state, 'unexpected end of the document within a single quoted scalar');
541
542
} else {
543
state.position++;
544
captureEnd = state.position;
545
}
546
}
547
548
throwError(state, 'unexpected end of the stream within a single quoted scalar');
549
}
550
551
function readDoubleQuotedScalar(state, nodeIndent) {
552
var captureStart,
553
captureEnd,
554
hexLength,
555
hexResult,
556
tmp, tmpEsc,
557
ch;
558
559
ch = state.input.charCodeAt(state.position);
560
561
if (0x22/* " */ !== ch) {
562
return false;
563
}
564
565
state.kind = 'scalar';
566
state.result = '';
567
state.position++;
568
captureStart = captureEnd = state.position;
569
570
while (0 !== (ch = state.input.charCodeAt(state.position))) {
571
if (0x22/* " */ === ch) {
572
captureSegment(state, captureStart, state.position, true);
573
state.position++;
574
return true;
575
576
} else if (0x5C/* \ */ === ch) {
577
captureSegment(state, captureStart, state.position, true);
578
ch = state.input.charCodeAt(++state.position);
579
580
if (is_EOL(ch)) {
581
skipSeparationSpace(state, false, nodeIndent);
582
583
// TODO: rework to inline fn with no type cast?
584
} else if (ch < 256 && simpleEscapeCheck[ch]) {
585
state.result += simpleEscapeMap[ch];
586
state.position++;
587
588
} else if ((tmp = escapedHexLen(ch)) > 0) {
589
hexLength = tmp;
590
hexResult = 0;
591
592
for (; hexLength > 0; hexLength--) {
593
ch = state.input.charCodeAt(++state.position);
594
595
if ((tmp = fromHexCode(ch)) >= 0) {
596
hexResult = (hexResult << 4) + tmp;
597
598
} else {
599
throwError(state, 'expected hexadecimal character');
600
}
601
}
602
603
state.result += charFromCodepoint(hexResult);
604
605
state.position++;
606
607
} else {
608
throwError(state, 'unknown escape sequence');
609
}
610
611
captureStart = captureEnd = state.position;
612
613
} else if (is_EOL(ch)) {
614
captureSegment(state, captureStart, captureEnd, true);
615
writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent));
616
captureStart = captureEnd = state.position;
617
618
} else if (state.position === state.lineStart && testDocumentSeparator(state)) {
619
throwError(state, 'unexpected end of the document within a double quoted scalar');
620
621
} else {
622
state.position++;
623
captureEnd = state.position;
624
}
625
}
626
627
throwError(state, 'unexpected end of the stream within a double quoted scalar');
628
}
629
630
function readFlowCollection(state, nodeIndent) {
631
var readNext = true,
632
_line,
633
_tag = state.tag,
634
_result,
635
_anchor = state.anchor,
636
following,
637
terminator,
638
isPair,
639
isExplicitPair,
640
isMapping,
641
keyNode,
642
keyTag,
643
valueNode,
644
ch;
645
646
ch = state.input.charCodeAt(state.position);
647
648
if (ch === 0x5B/* [ */) {
649
terminator = 0x5D;/* ] */
650
isMapping = false;
651
_result = [];
652
} else if (ch === 0x7B/* { */) {
653
terminator = 0x7D;/* } */
654
isMapping = true;
655
_result = {};
656
} else {
657
return false;
658
}
659
660
if (null !== state.anchor) {
661
state.anchorMap[state.anchor] = _result;
662
}
663
664
ch = state.input.charCodeAt(++state.position);
665
666
while (0 !== ch) {
667
skipSeparationSpace(state, true, nodeIndent);
668
669
ch = state.input.charCodeAt(state.position);
670
671
if (ch === terminator) {
672
state.position++;
673
state.tag = _tag;
674
state.anchor = _anchor;
675
state.kind = isMapping ? 'mapping' : 'sequence';
676
state.result = _result;
677
return true;
678
} else if (!readNext) {
679
throwError(state, 'missed comma between flow collection entries');
680
}
681
682
keyTag = keyNode = valueNode = null;
683
isPair = isExplicitPair = false;
684
685
if (0x3F/* ? */ === ch) {
686
following = state.input.charCodeAt(state.position + 1);
687
688
if (is_WS_OR_EOL(following)) {
689
isPair = isExplicitPair = true;
690
state.position++;
691
skipSeparationSpace(state, true, nodeIndent);
692
}
693
}
694
695
_line = state.line;
696
composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true);
697
keyTag = state.tag;
698
keyNode = state.result;
699
skipSeparationSpace(state, true, nodeIndent);
700
701
ch = state.input.charCodeAt(state.position);
702
703
if ((isExplicitPair || state.line === _line) && 0x3A/* : */ === ch) {
704
isPair = true;
705
ch = state.input.charCodeAt(++state.position);
706
skipSeparationSpace(state, true, nodeIndent);
707
composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true);
708
valueNode = state.result;
709
}
710
711
if (isMapping) {
712
storeMappingPair(state, _result, keyTag, keyNode, valueNode);
713
} else if (isPair) {
714
_result.push(storeMappingPair(state, null, keyTag, keyNode, valueNode));
715
} else {
716
_result.push(keyNode);
717
}
718
719
skipSeparationSpace(state, true, nodeIndent);
720
721
ch = state.input.charCodeAt(state.position);
722
723
if (0x2C/* , */ === ch) {
724
readNext = true;
725
ch = state.input.charCodeAt(++state.position);
726
} else {
727
readNext = false;
728
}
729
}
730
731
throwError(state, 'unexpected end of the stream within a flow collection');
732
}
733
734
function readBlockScalar(state, nodeIndent) {
735
var captureStart,
736
folding,
737
chomping = CHOMPING_CLIP,
738
detectedIndent = false,
739
textIndent = nodeIndent,
740
emptyLines = 0,
741
atMoreIndented = false,
742
tmp,
743
ch;
744
745
ch = state.input.charCodeAt(state.position);
746
747
if (ch === 0x7C/* | */) {
748
folding = false;
749
} else if (ch === 0x3E/* > */) {
750
folding = true;
751
} else {
752
return false;
753
}
754
755
state.kind = 'scalar';
756
state.result = '';
757
758
while (0 !== ch) {
759
ch = state.input.charCodeAt(++state.position);
760
761
if (0x2B/* + */ === ch || 0x2D/* - */ === ch) {
762
if (CHOMPING_CLIP === chomping) {
763
chomping = (0x2B/* + */ === ch) ? CHOMPING_KEEP : CHOMPING_STRIP;
764
} else {
765
throwError(state, 'repeat of a chomping mode identifier');
766
}
767
768
} else if ((tmp = fromDecimalCode(ch)) >= 0) {
769
if (tmp === 0) {
770
throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one');
771
} else if (!detectedIndent) {
772
textIndent = nodeIndent + tmp - 1;
773
detectedIndent = true;
774
} else {
775
throwError(state, 'repeat of an indentation width identifier');
776
}
777
778
} else {
779
break;
780
}
781
}
782
783
if (is_WHITE_SPACE(ch)) {
784
do { ch = state.input.charCodeAt(++state.position); }
785
while (is_WHITE_SPACE(ch));
786
787
if (0x23/* # */ === ch) {
788
do { ch = state.input.charCodeAt(++state.position); }
789
while (!is_EOL(ch) && (0 !== ch));
790
}
791
}
792
793
while (0 !== ch) {
794
readLineBreak(state);
795
state.lineIndent = 0;
796
797
ch = state.input.charCodeAt(state.position);
798
799
while ((!detectedIndent || state.lineIndent < textIndent) &&
800
(0x20/* Space */ === ch)) {
801
state.lineIndent++;
802
ch = state.input.charCodeAt(++state.position);
803
}
804
805
if (!detectedIndent && state.lineIndent > textIndent) {
806
textIndent = state.lineIndent;
807
}
808
809
if (is_EOL(ch)) {
810
emptyLines++;
811
continue;
812
}
813
814
// End of the scalar.
815
if (state.lineIndent < textIndent) {
816
817
// Perform the chomping.
818
if (chomping === CHOMPING_KEEP) {
819
state.result += common.repeat('\n', emptyLines);
820
} else if (chomping === CHOMPING_CLIP) {
821
if (detectedIndent) { // i.e. only if the scalar is not empty.
822
state.result += '\n';
823
}
824
}
825
826
// Break this `while` cycle and go to the funciton's epilogue.
827
break;
828
}
829
830
// Folded style: use fancy rules to handle line breaks.
831
if (folding) {
832
833
// Lines starting with white space characters (more-indented lines) are not folded.
834
if (is_WHITE_SPACE(ch)) {
835
atMoreIndented = true;
836
state.result += common.repeat('\n', emptyLines + 1);
837
838
// End of more-indented block.
839
} else if (atMoreIndented) {
840
atMoreIndented = false;
841
state.result += common.repeat('\n', emptyLines + 1);
842
843
// Just one line break - perceive as the same line.
844
} else if (0 === emptyLines) {
845
if (detectedIndent) { // i.e. only if we have already read some scalar content.
846
state.result += ' ';
847
}
848
849
// Several line breaks - perceive as different lines.
850
} else {
851
state.result += common.repeat('\n', emptyLines);
852
}
853
854
// Literal style: just add exact number of line breaks between content lines.
855
} else if (detectedIndent) {
856
// If current line isn't the first one - count line break from the last content line.
857
state.result += common.repeat('\n', emptyLines + 1);
858
} else {
859
// In case of the first content line - count only empty lines.
860
}
861
862
detectedIndent = true;
863
emptyLines = 0;
864
captureStart = state.position;
865
866
while (!is_EOL(ch) && (0 !== ch)) {
867
ch = state.input.charCodeAt(++state.position);
868
}
869
870
captureSegment(state, captureStart, state.position, false);
871
}
872
873
return true;
874
}
875
876
function readBlockSequence(state, nodeIndent) {
877
var _line,
878
_tag = state.tag,
879
_anchor = state.anchor,
880
_result = [],
881
following,
882
detected = false,
883
ch;
884
885
if (null !== state.anchor) {
886
state.anchorMap[state.anchor] = _result;
887
}
888
889
ch = state.input.charCodeAt(state.position);
890
891
while (0 !== ch) {
892
893
if (0x2D/* - */ !== ch) {
894
break;
895
}
896
897
following = state.input.charCodeAt(state.position + 1);
898
899
if (!is_WS_OR_EOL(following)) {
900
break;
901
}
902
903
detected = true;
904
state.position++;
905
906
if (skipSeparationSpace(state, true, -1)) {
907
if (state.lineIndent <= nodeIndent) {
908
_result.push(null);
909
ch = state.input.charCodeAt(state.position);
910
continue;
911
}
912
}
913
914
_line = state.line;
915
composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true);
916
_result.push(state.result);
917
skipSeparationSpace(state, true, -1);
918
919
ch = state.input.charCodeAt(state.position);
920
921
if ((state.line === _line || state.lineIndent > nodeIndent) && (0 !== ch)) {
922
throwError(state, 'bad indentation of a sequence entry');
923
} else if (state.lineIndent < nodeIndent) {
924
break;
925
}
926
}
927
928
if (detected) {
929
state.tag = _tag;
930
state.anchor = _anchor;
931
state.kind = 'sequence';
932
state.result = _result;
933
return true;
934
}
935
return false;
936
}
937
938
function readBlockMapping(state, nodeIndent, flowIndent) {
939
var following,
940
allowCompact,
941
_line,
942
_tag = state.tag,
943
_anchor = state.anchor,
944
_result = {},
945
keyTag = null,
946
keyNode = null,
947
valueNode = null,
948
atExplicitKey = false,
949
detected = false,
950
ch;
951
952
if (null !== state.anchor) {
953
state.anchorMap[state.anchor] = _result;
954
}
955
956
ch = state.input.charCodeAt(state.position);
957
958
while (0 !== ch) {
959
following = state.input.charCodeAt(state.position + 1);
960
_line = state.line; // Save the current line.
961
962
//
963
// Explicit notation case. There are two separate blocks:
964
// first for the key (denoted by "?") and second for the value (denoted by ":")
965
//
966
if ((0x3F/* ? */ === ch || 0x3A/* : */ === ch) && is_WS_OR_EOL(following)) {
967
968
if (0x3F/* ? */ === ch) {
969
if (atExplicitKey) {
970
storeMappingPair(state, _result, keyTag, keyNode, null);
971
keyTag = keyNode = valueNode = null;
972
}
973
974
detected = true;
975
atExplicitKey = true;
976
allowCompact = true;
977
978
} else if (atExplicitKey) {
979
// i.e. 0x3A/* : */ === character after the explicit key.
980
atExplicitKey = false;
981
allowCompact = true;
982
983
} else {
984
throwError(state, 'incomplete explicit mapping pair; a key node is missed');
985
}
986
987
state.position += 1;
988
ch = following;
989
990
//
991
// Implicit notation case. Flow-style node as the key first, then ":", and the value.
992
//
993
} else if (composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) {
994
995
if (state.line === _line) {
996
ch = state.input.charCodeAt(state.position);
997
998
while (is_WHITE_SPACE(ch)) {
999
ch = state.input.charCodeAt(++state.position);
1000
}
1001
1002
if (0x3A/* : */ === ch) {
1003
ch = state.input.charCodeAt(++state.position);
1004
1005
if (!is_WS_OR_EOL(ch)) {
1006
throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping');
1007
}
1008
1009
if (atExplicitKey) {
1010
storeMappingPair(state, _result, keyTag, keyNode, null);
1011
keyTag = keyNode = valueNode = null;
1012
}
1013
1014
detected = true;
1015
atExplicitKey = false;
1016
allowCompact = false;
1017
keyTag = state.tag;
1018
keyNode = state.result;
1019
1020
} else if (detected) {
1021
throwError(state, 'can not read an implicit mapping pair; a colon is missed');
1022
1023
} else {
1024
state.tag = _tag;
1025
state.anchor = _anchor;
1026
return true; // Keep the result of `composeNode`.
1027
}
1028
1029
} else if (detected) {
1030
throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key');
1031
1032
} else {
1033
state.tag = _tag;
1034
state.anchor = _anchor;
1035
return true; // Keep the result of `composeNode`.
1036
}
1037
1038
} else {
1039
break; // Reading is done. Go to the epilogue.
1040
}
1041
1042
//
1043
// Common reading code for both explicit and implicit notations.
1044
//
1045
if (state.line === _line || state.lineIndent > nodeIndent) {
1046
if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) {
1047
if (atExplicitKey) {
1048
keyNode = state.result;
1049
} else {
1050
valueNode = state.result;
1051
}
1052
}
1053
1054
if (!atExplicitKey) {
1055
storeMappingPair(state, _result, keyTag, keyNode, valueNode);
1056
keyTag = keyNode = valueNode = null;
1057
}
1058
1059
skipSeparationSpace(state, true, -1);
1060
ch = state.input.charCodeAt(state.position);
1061
}
1062
1063
if (state.lineIndent > nodeIndent && (0 !== ch)) {
1064
throwError(state, 'bad indentation of a mapping entry');
1065
} else if (state.lineIndent < nodeIndent) {
1066
break;
1067
}
1068
}
1069
1070
//
1071
// Epilogue.
1072
//
1073
1074
// Special case: last mapping's node contains only the key in explicit notation.
1075
if (atExplicitKey) {
1076
storeMappingPair(state, _result, keyTag, keyNode, null);
1077
}
1078
1079
// Expose the resulting mapping.
1080
if (detected) {
1081
state.tag = _tag;
1082
state.anchor = _anchor;
1083
state.kind = 'mapping';
1084
state.result = _result;
1085
}
1086
1087
return detected;
1088
}
1089
1090
function readTagProperty(state) {
1091
var _position,
1092
isVerbatim = false,
1093
isNamed = false,
1094
tagHandle,
1095
tagName,
1096
ch;
1097
1098
ch = state.input.charCodeAt(state.position);
1099
1100
if (0x21/* ! */ !== ch) {
1101
return false;
1102
}
1103
1104
if (null !== state.tag) {
1105
throwError(state, 'duplication of a tag property');
1106
}
1107
1108
ch = state.input.charCodeAt(++state.position);
1109
1110
if (0x3C/* < */ === ch) {
1111
isVerbatim = true;
1112
ch = state.input.charCodeAt(++state.position);
1113
1114
} else if (0x21/* ! */ === ch) {
1115
isNamed = true;
1116
tagHandle = '!!';
1117
ch = state.input.charCodeAt(++state.position);
1118
1119
} else {
1120
tagHandle = '!';
1121
}
1122
1123
_position = state.position;
1124
1125
if (isVerbatim) {
1126
do { ch = state.input.charCodeAt(++state.position); }
1127
while (0 !== ch && 0x3E/* > */ !== ch);
1128
1129
if (state.position < state.length) {
1130
tagName = state.input.slice(_position, state.position);
1131
ch = state.input.charCodeAt(++state.position);
1132
} else {
1133
throwError(state, 'unexpected end of the stream within a verbatim tag');
1134
}
1135
} else {
1136
while (0 !== ch && !is_WS_OR_EOL(ch)) {
1137
1138
if (0x21/* ! */ === ch) {
1139
if (!isNamed) {
1140
tagHandle = state.input.slice(_position - 1, state.position + 1);
1141
1142
if (!PATTERN_TAG_HANDLE.test(tagHandle)) {
1143
throwError(state, 'named tag handle cannot contain such characters');
1144
}
1145
1146
isNamed = true;
1147
_position = state.position + 1;
1148
} else {
1149
throwError(state, 'tag suffix cannot contain exclamation marks');
1150
}
1151
}
1152
1153
ch = state.input.charCodeAt(++state.position);
1154
}
1155
1156
tagName = state.input.slice(_position, state.position);
1157
1158
if (PATTERN_FLOW_INDICATORS.test(tagName)) {
1159
throwError(state, 'tag suffix cannot contain flow indicator characters');
1160
}
1161
}
1162
1163
if (tagName && !PATTERN_TAG_URI.test(tagName)) {
1164
throwError(state, 'tag name cannot contain such characters: ' + tagName);
1165
}
1166
1167
if (isVerbatim) {
1168
state.tag = tagName;
1169
1170
} else if (_hasOwnProperty.call(state.tagMap, tagHandle)) {
1171
state.tag = state.tagMap[tagHandle] + tagName;
1172
1173
} else if ('!' === tagHandle) {
1174
state.tag = '!' + tagName;
1175
1176
} else if ('!!' === tagHandle) {
1177
state.tag = 'tag:yaml.org,2002:' + tagName;
1178
1179
} else {
1180
throwError(state, 'undeclared tag handle "' + tagHandle + '"');
1181
}
1182
1183
return true;
1184
}
1185
1186
function readAnchorProperty(state) {
1187
var _position,
1188
ch;
1189
1190
ch = state.input.charCodeAt(state.position);
1191
1192
if (0x26/* & */ !== ch) {
1193
return false;
1194
}
1195
1196
if (null !== state.anchor) {
1197
throwError(state, 'duplication of an anchor property');
1198
}
1199
1200
ch = state.input.charCodeAt(++state.position);
1201
_position = state.position;
1202
1203
while (0 !== ch && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) {
1204
ch = state.input.charCodeAt(++state.position);
1205
}
1206
1207
if (state.position === _position) {
1208
throwError(state, 'name of an anchor node must contain at least one character');
1209
}
1210
1211
state.anchor = state.input.slice(_position, state.position);
1212
return true;
1213
}
1214
1215
function readAlias(state) {
1216
var _position, alias,
1217
len = state.length,
1218
input = state.input,
1219
ch;
1220
1221
ch = state.input.charCodeAt(state.position);
1222
1223
if (0x2A/* * */ !== ch) {
1224
return false;
1225
}
1226
1227
ch = state.input.charCodeAt(++state.position);
1228
_position = state.position;
1229
1230
while (0 !== ch && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) {
1231
ch = state.input.charCodeAt(++state.position);
1232
}
1233
1234
if (state.position === _position) {
1235
throwError(state, 'name of an alias node must contain at least one character');
1236
}
1237
1238
alias = state.input.slice(_position, state.position);
1239
1240
if (!state.anchorMap.hasOwnProperty(alias)) {
1241
throwError(state, 'unidentified alias "' + alias + '"');
1242
}
1243
1244
state.result = state.anchorMap[alias];
1245
skipSeparationSpace(state, true, -1);
1246
return true;
1247
}
1248
1249
function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) {
1250
var allowBlockStyles,
1251
allowBlockScalars,
1252
allowBlockCollections,
1253
indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this<parent
1254
atNewLine = false,
1255
hasContent = false,
1256
typeIndex,
1257
typeQuantity,
1258
type,
1259
flowIndent,
1260
blockIndent,
1261
_result;
1262
1263
state.tag = null;
1264
state.anchor = null;
1265
state.kind = null;
1266
state.result = null;
1267
1268
allowBlockStyles = allowBlockScalars = allowBlockCollections =
1269
CONTEXT_BLOCK_OUT === nodeContext ||
1270
CONTEXT_BLOCK_IN === nodeContext;
1271
1272
if (allowToSeek) {
1273
if (skipSeparationSpace(state, true, -1)) {
1274
atNewLine = true;
1275
1276
if (state.lineIndent > parentIndent) {
1277
indentStatus = 1;
1278
} else if (state.lineIndent === parentIndent) {
1279
indentStatus = 0;
1280
} else if (state.lineIndent < parentIndent) {
1281
indentStatus = -1;
1282
}
1283
}
1284
}
1285
1286
if (1 === indentStatus) {
1287
while (readTagProperty(state) || readAnchorProperty(state)) {
1288
if (skipSeparationSpace(state, true, -1)) {
1289
atNewLine = true;
1290
allowBlockCollections = allowBlockStyles;
1291
1292
if (state.lineIndent > parentIndent) {
1293
indentStatus = 1;
1294
} else if (state.lineIndent === parentIndent) {
1295
indentStatus = 0;
1296
} else if (state.lineIndent < parentIndent) {
1297
indentStatus = -1;
1298
}
1299
} else {
1300
allowBlockCollections = false;
1301
}
1302
}
1303
}
1304
1305
if (allowBlockCollections) {
1306
allowBlockCollections = atNewLine || allowCompact;
1307
}
1308
1309
if (1 === indentStatus || CONTEXT_BLOCK_OUT === nodeContext) {
1310
if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) {
1311
flowIndent = parentIndent;
1312
} else {
1313
flowIndent = parentIndent + 1;
1314
}
1315
1316
blockIndent = state.position - state.lineStart;
1317
1318
if (1 === indentStatus) {
1319
if (allowBlockCollections &&
1320
(readBlockSequence(state, blockIndent) ||
1321
readBlockMapping(state, blockIndent, flowIndent)) ||
1322
readFlowCollection(state, flowIndent)) {
1323
hasContent = true;
1324
} else {
1325
if ((allowBlockScalars && readBlockScalar(state, flowIndent)) ||
1326
readSingleQuotedScalar(state, flowIndent) ||
1327
readDoubleQuotedScalar(state, flowIndent)) {
1328
hasContent = true;
1329
1330
} else if (readAlias(state)) {
1331
hasContent = true;
1332
1333
if (null !== state.tag || null !== state.anchor) {
1334
throwError(state, 'alias node should not have any properties');
1335
}
1336
1337
} else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) {
1338
hasContent = true;
1339
1340
if (null === state.tag) {
1341
state.tag = '?';
1342
}
1343
}
1344
1345
if (null !== state.anchor) {
1346
state.anchorMap[state.anchor] = state.result;
1347
}
1348
}
1349
} else if (0 === indentStatus) {
1350
// Special case: block sequences are allowed to have same indentation level as the parent.
1351
// http://www.yaml.org/spec/1.2/spec.html#id2799784
1352
hasContent = allowBlockCollections && readBlockSequence(state, blockIndent);
1353
}
1354
}
1355
1356
if (null !== state.tag && '!' !== state.tag) {
1357
if ('?' === state.tag) {
1358
for (typeIndex = 0, typeQuantity = state.implicitTypes.length;
1359
typeIndex < typeQuantity;
1360
typeIndex += 1) {
1361
type = state.implicitTypes[typeIndex];
1362
1363
// Implicit resolving is not allowed for non-scalar types, and '?'
1364
// non-specific tag is only assigned to plain scalars. So, it isn't
1365
// needed to check for 'kind' conformity.
1366
1367
if (type.resolve(state.result)) { // `state.result` updated in resolver if matched
1368
state.result = type.construct(state.result);
1369
state.tag = type.tag;
1370
if (null !== state.anchor) {
1371
state.anchorMap[state.anchor] = state.result;
1372
}
1373
break;
1374
}
1375
}
1376
} else if (_hasOwnProperty.call(state.typeMap, state.tag)) {
1377
type = state.typeMap[state.tag];
1378
1379
if (null !== state.result && type.kind !== state.kind) {
1380
throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"');
1381
}
1382
1383
if (!type.resolve(state.result)) { // `state.result` updated in resolver if matched
1384
throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag');
1385
} else {
1386
state.result = type.construct(state.result);
1387
if (null !== state.anchor) {
1388
state.anchorMap[state.anchor] = state.result;
1389
}
1390
}
1391
} else {
1392
throwWarning(state, 'unknown tag !<' + state.tag + '>');
1393
}
1394
}
1395
1396
return null !== state.tag || null !== state.anchor || hasContent;
1397
}
1398
1399
function readDocument(state) {
1400
var documentStart = state.position,
1401
_position,
1402
directiveName,
1403
directiveArgs,
1404
hasDirectives = false,
1405
ch;
1406
1407
state.version = null;
1408
state.checkLineBreaks = state.legacy;
1409
state.tagMap = {};
1410
state.anchorMap = {};
1411
1412
while (0 !== (ch = state.input.charCodeAt(state.position))) {
1413
skipSeparationSpace(state, true, -1);
1414
1415
ch = state.input.charCodeAt(state.position);
1416
1417
if (state.lineIndent > 0 || 0x25/* % */ !== ch) {
1418
break;
1419
}
1420
1421
hasDirectives = true;
1422
ch = state.input.charCodeAt(++state.position);
1423
_position = state.position;
1424
1425
while (0 !== ch && !is_WS_OR_EOL(ch)) {
1426
ch = state.input.charCodeAt(++state.position);
1427
}
1428
1429
directiveName = state.input.slice(_position, state.position);
1430
directiveArgs = [];
1431
1432
if (directiveName.length < 1) {
1433
throwError(state, 'directive name must not be less than one character in length');
1434
}
1435
1436
while (0 !== ch) {
1437
while (is_WHITE_SPACE(ch)) {
1438
ch = state.input.charCodeAt(++state.position);
1439
}
1440
1441
if (0x23/* # */ === ch) {
1442
do { ch = state.input.charCodeAt(++state.position); }
1443
while (0 !== ch && !is_EOL(ch));
1444
break;
1445
}
1446
1447
if (is_EOL(ch)) {
1448
break;
1449
}
1450
1451
_position = state.position;
1452
1453
while (0 !== ch && !is_WS_OR_EOL(ch)) {
1454
ch = state.input.charCodeAt(++state.position);
1455
}
1456
1457
directiveArgs.push(state.input.slice(_position, state.position));
1458
}
1459
1460
if (0 !== ch) {
1461
readLineBreak(state);
1462
}
1463
1464
if (_hasOwnProperty.call(directiveHandlers, directiveName)) {
1465
directiveHandlers[directiveName](state, directiveName, directiveArgs);
1466
} else {
1467
throwWarning(state, 'unknown document directive "' + directiveName + '"');
1468
}
1469
}
1470
1471
skipSeparationSpace(state, true, -1);
1472
1473
if (0 === state.lineIndent &&
1474
0x2D/* - */ === state.input.charCodeAt(state.position) &&
1475
0x2D/* - */ === state.input.charCodeAt(state.position + 1) &&
1476
0x2D/* - */ === state.input.charCodeAt(state.position + 2)) {
1477
state.position += 3;
1478
skipSeparationSpace(state, true, -1);
1479
1480
} else if (hasDirectives) {
1481
throwError(state, 'directives end mark is expected');
1482
}
1483
1484
composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true);
1485
skipSeparationSpace(state, true, -1);
1486
1487
if (state.checkLineBreaks &&
1488
PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) {
1489
throwWarning(state, 'non-ASCII line breaks are interpreted as content');
1490
}
1491
1492
state.documents.push(state.result);
1493
1494
if (state.position === state.lineStart && testDocumentSeparator(state)) {
1495
1496
if (0x2E/* . */ === state.input.charCodeAt(state.position)) {
1497
state.position += 3;
1498
skipSeparationSpace(state, true, -1);
1499
}
1500
return;
1501
}
1502
1503
if (state.position < (state.length - 1)) {
1504
throwError(state, 'end of the stream or a document separator is expected');
1505
} else {
1506
return;
1507
}
1508
}
1509
1510
1511
function loadDocuments(input, options) {
1512
input = String(input);
1513
options = options || {};
1514
1515
if (input.length !== 0) {
1516
1517
// Add tailing `\n` if not exists
1518
if (0x0A/* LF */ !== input.charCodeAt(input.length - 1) &&
1519
0x0D/* CR */ !== input.charCodeAt(input.length - 1)) {
1520
input += '\n';
1521
}
1522
1523
// Strip BOM
1524
if (input.charCodeAt(0) === 0xFEFF) {
1525
input = input.slice(1);
1526
}
1527
}
1528
1529
var state = new State(input, options);
1530
1531
if (PATTERN_NON_PRINTABLE.test(state.input)) {
1532
throwError(state, 'the stream contains non-printable characters');
1533
}
1534
1535
// Use 0 as string terminator. That significantly simplifies bounds check.
1536
state.input += '\0';
1537
1538
while (0x20/* Space */ === state.input.charCodeAt(state.position)) {
1539
state.lineIndent += 1;
1540
state.position += 1;
1541
}
1542
1543
while (state.position < (state.length - 1)) {
1544
readDocument(state);
1545
}
1546
1547
return state.documents;
1548
}
1549
1550
1551
function loadAll(input, iterator, options) {
1552
var documents = loadDocuments(input, options), index, length;
1553
1554
for (index = 0, length = documents.length; index < length; index += 1) {
1555
iterator(documents[index]);
1556
}
1557
}
1558
1559
1560
function load(input, options) {
1561
var documents = loadDocuments(input, options), index, length;
1562
1563
if (0 === documents.length) {
1564
/*eslint-disable no-undefined*/
1565
return undefined;
1566
} else if (1 === documents.length) {
1567
return documents[0];
1568
}
1569
throw new YAMLException('expected a single document in the stream, but found more');
1570
}
1571
1572
1573
function safeLoadAll(input, output, options) {
1574
loadAll(input, output, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
1575
}
1576
1577
1578
function safeLoad(input, options) {
1579
return load(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
1580
}
1581
1582
1583
module.exports.loadAll = loadAll;
1584
module.exports.load = load;
1585
module.exports.safeLoadAll = safeLoadAll;
1586
module.exports.safeLoad = safeLoad;
1587
1588