loader.js (44356B)
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 (!state.anchorMap.hasOwnProperty(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;