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