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