Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80698 views
1
'use strict';
2
3
/*eslint-disable no-use-before-define*/
4
5
var common = require('./common');
6
var YAMLException = require('./exception');
7
var DEFAULT_FULL_SCHEMA = require('./schema/default_full');
8
var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe');
9
10
var _toString = Object.prototype.toString;
11
var _hasOwnProperty = Object.prototype.hasOwnProperty;
12
13
var CHAR_TAB = 0x09; /* Tab */
14
var CHAR_LINE_FEED = 0x0A; /* LF */
15
var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */
16
var CHAR_SPACE = 0x20; /* Space */
17
var CHAR_EXCLAMATION = 0x21; /* ! */
18
var CHAR_DOUBLE_QUOTE = 0x22; /* " */
19
var CHAR_SHARP = 0x23; /* # */
20
var CHAR_PERCENT = 0x25; /* % */
21
var CHAR_AMPERSAND = 0x26; /* & */
22
var CHAR_SINGLE_QUOTE = 0x27; /* ' */
23
var CHAR_ASTERISK = 0x2A; /* * */
24
var CHAR_COMMA = 0x2C; /* , */
25
var CHAR_MINUS = 0x2D; /* - */
26
var CHAR_COLON = 0x3A; /* : */
27
var CHAR_GREATER_THAN = 0x3E; /* > */
28
var CHAR_QUESTION = 0x3F; /* ? */
29
var CHAR_COMMERCIAL_AT = 0x40; /* @ */
30
var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */
31
var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */
32
var CHAR_GRAVE_ACCENT = 0x60; /* ` */
33
var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */
34
var CHAR_VERTICAL_LINE = 0x7C; /* | */
35
var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */
36
37
var ESCAPE_SEQUENCES = {};
38
39
ESCAPE_SEQUENCES[0x00] = '\\0';
40
ESCAPE_SEQUENCES[0x07] = '\\a';
41
ESCAPE_SEQUENCES[0x08] = '\\b';
42
ESCAPE_SEQUENCES[0x09] = '\\t';
43
ESCAPE_SEQUENCES[0x0A] = '\\n';
44
ESCAPE_SEQUENCES[0x0B] = '\\v';
45
ESCAPE_SEQUENCES[0x0C] = '\\f';
46
ESCAPE_SEQUENCES[0x0D] = '\\r';
47
ESCAPE_SEQUENCES[0x1B] = '\\e';
48
ESCAPE_SEQUENCES[0x22] = '\\"';
49
ESCAPE_SEQUENCES[0x5C] = '\\\\';
50
ESCAPE_SEQUENCES[0x85] = '\\N';
51
ESCAPE_SEQUENCES[0xA0] = '\\_';
52
ESCAPE_SEQUENCES[0x2028] = '\\L';
53
ESCAPE_SEQUENCES[0x2029] = '\\P';
54
55
var DEPRECATED_BOOLEANS_SYNTAX = [
56
'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON',
57
'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'
58
];
59
60
function compileStyleMap(schema, map) {
61
var result, keys, index, length, tag, style, type;
62
63
if (null === map) {
64
return {};
65
}
66
67
result = {};
68
keys = Object.keys(map);
69
70
for (index = 0, length = keys.length; index < length; index += 1) {
71
tag = keys[index];
72
style = String(map[tag]);
73
74
if ('!!' === tag.slice(0, 2)) {
75
tag = 'tag:yaml.org,2002:' + tag.slice(2);
76
}
77
78
type = schema.compiledTypeMap[tag];
79
80
if (type && _hasOwnProperty.call(type.styleAliases, style)) {
81
style = type.styleAliases[style];
82
}
83
84
result[tag] = style;
85
}
86
87
return result;
88
}
89
90
function encodeHex(character) {
91
var string, handle, length;
92
93
string = character.toString(16).toUpperCase();
94
95
if (character <= 0xFF) {
96
handle = 'x';
97
length = 2;
98
} else if (character <= 0xFFFF) {
99
handle = 'u';
100
length = 4;
101
} else if (character <= 0xFFFFFFFF) {
102
handle = 'U';
103
length = 8;
104
} else {
105
throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF');
106
}
107
108
return '\\' + handle + common.repeat('0', length - string.length) + string;
109
}
110
111
function State(options) {
112
this.schema = options['schema'] || DEFAULT_FULL_SCHEMA;
113
this.indent = Math.max(1, (options['indent'] || 2));
114
this.skipInvalid = options['skipInvalid'] || false;
115
this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']);
116
this.styleMap = compileStyleMap(this.schema, options['styles'] || null);
117
this.sortKeys = options['sortKeys'] || false;
118
119
this.implicitTypes = this.schema.compiledImplicit;
120
this.explicitTypes = this.schema.compiledExplicit;
121
122
this.tag = null;
123
this.result = '';
124
125
this.duplicates = [];
126
this.usedDuplicates = null;
127
}
128
129
function indentString(string, spaces) {
130
var ind = common.repeat(' ', spaces),
131
position = 0,
132
next = -1,
133
result = '',
134
line,
135
length = string.length;
136
137
while (position < length) {
138
next = string.indexOf('\n', position);
139
if (next === -1) {
140
line = string.slice(position);
141
position = length;
142
} else {
143
line = string.slice(position, next + 1);
144
position = next + 1;
145
}
146
if (line.length && line !== '\n') {
147
result += ind;
148
}
149
result += line;
150
}
151
152
return result;
153
}
154
155
function generateNextLine(state, level) {
156
return '\n' + common.repeat(' ', state.indent * level);
157
}
158
159
function testImplicitResolving(state, str) {
160
var index, length, type;
161
162
for (index = 0, length = state.implicitTypes.length; index < length; index += 1) {
163
type = state.implicitTypes[index];
164
165
if (type.resolve(str)) {
166
return true;
167
}
168
}
169
170
return false;
171
}
172
173
function StringBuilder(source) {
174
this.source = source;
175
this.result = '';
176
this.checkpoint = 0;
177
}
178
179
StringBuilder.prototype.takeUpTo = function (position) {
180
var er;
181
182
if (position < this.checkpoint) {
183
er = new Error('position should be > checkpoint');
184
er.position = position;
185
er.checkpoint = this.checkpoint;
186
throw er;
187
}
188
189
this.result += this.source.slice(this.checkpoint, position);
190
this.checkpoint = position;
191
return this;
192
};
193
194
StringBuilder.prototype.escapeChar = function () {
195
var character, esc;
196
197
character = this.source.charCodeAt(this.checkpoint);
198
esc = ESCAPE_SEQUENCES[character] || encodeHex(character);
199
this.result += esc;
200
this.checkpoint += 1;
201
202
return this;
203
};
204
205
StringBuilder.prototype.finish = function () {
206
if (this.source.length > this.checkpoint) {
207
this.takeUpTo(this.source.length);
208
}
209
};
210
211
function writeScalar(state, object, level) {
212
var simple, first, spaceWrap, folded, literal, single, double,
213
sawLineFeed, linePosition, longestLine, indent, max, character,
214
position, escapeSeq, hexEsc, previous, lineLength, modifier,
215
trailingLineBreaks, result;
216
217
if (0 === object.length) {
218
state.dump = "''";
219
return;
220
}
221
222
if (-1 !== DEPRECATED_BOOLEANS_SYNTAX.indexOf(object)) {
223
state.dump = "'" + object + "'";
224
return;
225
}
226
227
simple = true;
228
first = object.length ? object.charCodeAt(0) : 0;
229
spaceWrap = (CHAR_SPACE === first ||
230
CHAR_SPACE === object.charCodeAt(object.length - 1));
231
232
// Simplified check for restricted first characters
233
// http://www.yaml.org/spec/1.2/spec.html#ns-plain-first%28c%29
234
if (CHAR_MINUS === first ||
235
CHAR_QUESTION === first ||
236
CHAR_COMMERCIAL_AT === first ||
237
CHAR_GRAVE_ACCENT === first) {
238
simple = false;
239
}
240
241
// can only use > and | if not wrapped in spaces.
242
if (spaceWrap) {
243
simple = false;
244
folded = false;
245
literal = false;
246
} else {
247
folded = true;
248
literal = true;
249
}
250
251
single = true;
252
double = new StringBuilder(object);
253
254
sawLineFeed = false;
255
linePosition = 0;
256
longestLine = 0;
257
258
indent = state.indent * level;
259
max = 80;
260
if (indent < 40) {
261
max -= indent;
262
} else {
263
max = 40;
264
}
265
266
for (position = 0; position < object.length; position++) {
267
character = object.charCodeAt(position);
268
if (simple) {
269
// Characters that can never appear in the simple scalar
270
if (!simpleChar(character)) {
271
simple = false;
272
} else {
273
// Still simple. If we make it all the way through like
274
// this, then we can just dump the string as-is.
275
continue;
276
}
277
}
278
279
if (single && character === CHAR_SINGLE_QUOTE) {
280
single = false;
281
}
282
283
escapeSeq = ESCAPE_SEQUENCES[character];
284
hexEsc = needsHexEscape(character);
285
286
if (!escapeSeq && !hexEsc) {
287
continue;
288
}
289
290
if (character !== CHAR_LINE_FEED &&
291
character !== CHAR_DOUBLE_QUOTE &&
292
character !== CHAR_SINGLE_QUOTE) {
293
folded = false;
294
literal = false;
295
} else if (character === CHAR_LINE_FEED) {
296
sawLineFeed = true;
297
single = false;
298
if (position > 0) {
299
previous = object.charCodeAt(position - 1);
300
if (previous === CHAR_SPACE) {
301
literal = false;
302
folded = false;
303
}
304
}
305
if (folded) {
306
lineLength = position - linePosition;
307
linePosition = position;
308
if (lineLength > longestLine) {
309
longestLine = lineLength;
310
}
311
}
312
}
313
314
if (character !== CHAR_DOUBLE_QUOTE) {
315
single = false;
316
}
317
318
double.takeUpTo(position);
319
double.escapeChar();
320
}
321
322
if (simple && testImplicitResolving(state, object)) {
323
simple = false;
324
}
325
326
modifier = '';
327
if (folded || literal) {
328
trailingLineBreaks = 0;
329
if (object.charCodeAt(object.length - 1) === CHAR_LINE_FEED) {
330
trailingLineBreaks += 1;
331
if (object.charCodeAt(object.length - 2) === CHAR_LINE_FEED) {
332
trailingLineBreaks += 1;
333
}
334
}
335
336
if (trailingLineBreaks === 0) {
337
modifier = '-';
338
} else if (trailingLineBreaks === 2) {
339
modifier = '+';
340
}
341
}
342
343
if (literal && longestLine < max) {
344
folded = false;
345
}
346
347
// If it's literally one line, then don't bother with the literal.
348
// We may still want to do a fold, though, if it's a super long line.
349
if (!sawLineFeed) {
350
literal = false;
351
}
352
353
if (simple) {
354
state.dump = object;
355
} else if (single) {
356
state.dump = '\'' + object + '\'';
357
} else if (folded) {
358
result = fold(object, max);
359
state.dump = '>' + modifier + '\n' + indentString(result, indent);
360
} else if (literal) {
361
if (!modifier) {
362
object = object.replace(/\n$/, '');
363
}
364
state.dump = '|' + modifier + '\n' + indentString(object, indent);
365
} else if (double) {
366
double.finish();
367
state.dump = '"' + double.result + '"';
368
} else {
369
throw new Error('Failed to dump scalar value');
370
}
371
372
return;
373
}
374
375
// The `trailing` var is a regexp match of any trailing `\n` characters.
376
//
377
// There are three cases we care about:
378
//
379
// 1. One trailing `\n` on the string. Just use `|` or `>`.
380
// This is the assumed default. (trailing = null)
381
// 2. No trailing `\n` on the string. Use `|-` or `>-` to "chomp" the end.
382
// 3. More than one trailing `\n` on the string. Use `|+` or `>+`.
383
//
384
// In the case of `>+`, these line breaks are *not* doubled (like the line
385
// breaks within the string), so it's important to only end with the exact
386
// same number as we started.
387
function fold(object, max) {
388
var result = '',
389
position = 0,
390
length = object.length,
391
trailing = /\n+$/.exec(object),
392
newLine;
393
394
if (trailing) {
395
length = trailing.index + 1;
396
}
397
398
while (position < length) {
399
newLine = object.indexOf('\n', position);
400
if (newLine > length || newLine === -1) {
401
if (result) {
402
result += '\n\n';
403
}
404
result += foldLine(object.slice(position, length), max);
405
position = length;
406
} else {
407
if (result) {
408
result += '\n\n';
409
}
410
result += foldLine(object.slice(position, newLine), max);
411
position = newLine + 1;
412
}
413
}
414
if (trailing && trailing[0] !== '\n') {
415
result += trailing[0];
416
}
417
418
return result;
419
}
420
421
function foldLine(line, max) {
422
if (line === '') {
423
return line;
424
}
425
426
var foldRe = /[^\s] [^\s]/g,
427
result = '',
428
prevMatch = 0,
429
foldStart = 0,
430
match = foldRe.exec(line),
431
index,
432
foldEnd,
433
folded;
434
435
while (match) {
436
index = match.index;
437
438
// when we cross the max len, if the previous match would've
439
// been ok, use that one, and carry on. If there was no previous
440
// match on this fold section, then just have a long line.
441
if (index - foldStart > max) {
442
if (prevMatch !== foldStart) {
443
foldEnd = prevMatch;
444
} else {
445
foldEnd = index;
446
}
447
448
if (result) {
449
result += '\n';
450
}
451
folded = line.slice(foldStart, foldEnd);
452
result += folded;
453
foldStart = foldEnd + 1;
454
}
455
prevMatch = index + 1;
456
match = foldRe.exec(line);
457
}
458
459
if (result) {
460
result += '\n';
461
}
462
463
// if we end up with one last word at the end, then the last bit might
464
// be slightly bigger than we wanted, because we exited out of the loop.
465
if (foldStart !== prevMatch && line.length - foldStart > max) {
466
result += line.slice(foldStart, prevMatch) + '\n' +
467
line.slice(prevMatch + 1);
468
} else {
469
result += line.slice(foldStart);
470
}
471
472
return result;
473
}
474
475
// Returns true if character can be found in a simple scalar
476
function simpleChar(character) {
477
return CHAR_TAB !== character &&
478
CHAR_LINE_FEED !== character &&
479
CHAR_CARRIAGE_RETURN !== character &&
480
CHAR_COMMA !== character &&
481
CHAR_LEFT_SQUARE_BRACKET !== character &&
482
CHAR_RIGHT_SQUARE_BRACKET !== character &&
483
CHAR_LEFT_CURLY_BRACKET !== character &&
484
CHAR_RIGHT_CURLY_BRACKET !== character &&
485
CHAR_SHARP !== character &&
486
CHAR_AMPERSAND !== character &&
487
CHAR_ASTERISK !== character &&
488
CHAR_EXCLAMATION !== character &&
489
CHAR_VERTICAL_LINE !== character &&
490
CHAR_GREATER_THAN !== character &&
491
CHAR_SINGLE_QUOTE !== character &&
492
CHAR_DOUBLE_QUOTE !== character &&
493
CHAR_PERCENT !== character &&
494
CHAR_COLON !== character &&
495
!ESCAPE_SEQUENCES[character] &&
496
!needsHexEscape(character);
497
}
498
499
// Returns true if the character code needs to be escaped.
500
function needsHexEscape(character) {
501
return !((0x00020 <= character && character <= 0x00007E) ||
502
(0x00085 === character) ||
503
(0x000A0 <= character && character <= 0x00D7FF) ||
504
(0x0E000 <= character && character <= 0x00FFFD) ||
505
(0x10000 <= character && character <= 0x10FFFF));
506
}
507
508
function writeFlowSequence(state, level, object) {
509
var _result = '',
510
_tag = state.tag,
511
index,
512
length;
513
514
for (index = 0, length = object.length; index < length; index += 1) {
515
// Write only valid elements.
516
if (writeNode(state, level, object[index], false, false)) {
517
if (0 !== index) {
518
_result += ', ';
519
}
520
_result += state.dump;
521
}
522
}
523
524
state.tag = _tag;
525
state.dump = '[' + _result + ']';
526
}
527
528
function writeBlockSequence(state, level, object, compact) {
529
var _result = '',
530
_tag = state.tag,
531
index,
532
length;
533
534
for (index = 0, length = object.length; index < length; index += 1) {
535
// Write only valid elements.
536
if (writeNode(state, level + 1, object[index], true, true)) {
537
if (!compact || 0 !== index) {
538
_result += generateNextLine(state, level);
539
}
540
_result += '- ' + state.dump;
541
}
542
}
543
544
state.tag = _tag;
545
state.dump = _result || '[]'; // Empty sequence if no valid values.
546
}
547
548
function writeFlowMapping(state, level, object) {
549
var _result = '',
550
_tag = state.tag,
551
objectKeyList = Object.keys(object),
552
index,
553
length,
554
objectKey,
555
objectValue,
556
pairBuffer;
557
558
for (index = 0, length = objectKeyList.length; index < length; index += 1) {
559
pairBuffer = '';
560
561
if (0 !== index) {
562
pairBuffer += ', ';
563
}
564
565
objectKey = objectKeyList[index];
566
objectValue = object[objectKey];
567
568
if (!writeNode(state, level, objectKey, false, false)) {
569
continue; // Skip this pair because of invalid key;
570
}
571
572
if (state.dump.length > 1024) {
573
pairBuffer += '? ';
574
}
575
576
pairBuffer += state.dump + ': ';
577
578
if (!writeNode(state, level, objectValue, false, false)) {
579
continue; // Skip this pair because of invalid value.
580
}
581
582
pairBuffer += state.dump;
583
584
// Both key and value are valid.
585
_result += pairBuffer;
586
}
587
588
state.tag = _tag;
589
state.dump = '{' + _result + '}';
590
}
591
592
function writeBlockMapping(state, level, object, compact) {
593
var _result = '',
594
_tag = state.tag,
595
objectKeyList = Object.keys(object),
596
index,
597
length,
598
objectKey,
599
objectValue,
600
explicitPair,
601
pairBuffer;
602
603
// Allow sorting keys so that the output file is deterministic
604
if (state.sortKeys === true) {
605
// Default sorting
606
objectKeyList.sort();
607
} else if (typeof state.sortKeys === 'function') {
608
// Custom sort function
609
objectKeyList.sort(state.sortKeys);
610
} else if (state.sortKeys) {
611
// Something is wrong
612
throw new YAMLException('sortKeys must be a boolean or a function');
613
}
614
615
for (index = 0, length = objectKeyList.length; index < length; index += 1) {
616
pairBuffer = '';
617
618
if (!compact || 0 !== index) {
619
pairBuffer += generateNextLine(state, level);
620
}
621
622
objectKey = objectKeyList[index];
623
objectValue = object[objectKey];
624
625
if (!writeNode(state, level + 1, objectKey, true, true)) {
626
continue; // Skip this pair because of invalid key.
627
}
628
629
explicitPair = (null !== state.tag && '?' !== state.tag) ||
630
(state.dump && state.dump.length > 1024);
631
632
if (explicitPair) {
633
if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
634
pairBuffer += '?';
635
} else {
636
pairBuffer += '? ';
637
}
638
}
639
640
pairBuffer += state.dump;
641
642
if (explicitPair) {
643
pairBuffer += generateNextLine(state, level);
644
}
645
646
if (!writeNode(state, level + 1, objectValue, true, explicitPair)) {
647
continue; // Skip this pair because of invalid value.
648
}
649
650
if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
651
pairBuffer += ':';
652
} else {
653
pairBuffer += ': ';
654
}
655
656
pairBuffer += state.dump;
657
658
// Both key and value are valid.
659
_result += pairBuffer;
660
}
661
662
state.tag = _tag;
663
state.dump = _result || '{}'; // Empty mapping if no valid pairs.
664
}
665
666
function detectType(state, object, explicit) {
667
var _result, typeList, index, length, type, style;
668
669
typeList = explicit ? state.explicitTypes : state.implicitTypes;
670
671
for (index = 0, length = typeList.length; index < length; index += 1) {
672
type = typeList[index];
673
674
if ((type.instanceOf || type.predicate) &&
675
(!type.instanceOf || (('object' === typeof object) && (object instanceof type.instanceOf))) &&
676
(!type.predicate || type.predicate(object))) {
677
678
state.tag = explicit ? type.tag : '?';
679
680
if (type.represent) {
681
style = state.styleMap[type.tag] || type.defaultStyle;
682
683
if ('[object Function]' === _toString.call(type.represent)) {
684
_result = type.represent(object, style);
685
} else if (_hasOwnProperty.call(type.represent, style)) {
686
_result = type.represent[style](object, style);
687
} else {
688
throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
689
}
690
691
state.dump = _result;
692
}
693
694
return true;
695
}
696
}
697
698
return false;
699
}
700
701
// Serializes `object` and writes it to global `result`.
702
// Returns true on success, or false on invalid object.
703
//
704
function writeNode(state, level, object, block, compact) {
705
state.tag = null;
706
state.dump = object;
707
708
if (!detectType(state, object, false)) {
709
detectType(state, object, true);
710
}
711
712
var type = _toString.call(state.dump);
713
714
if (block) {
715
block = (0 > state.flowLevel || state.flowLevel > level);
716
}
717
718
if ((null !== state.tag && '?' !== state.tag) || (2 !== state.indent && level > 0)) {
719
compact = false;
720
}
721
722
var objectOrArray = '[object Object]' === type || '[object Array]' === type,
723
duplicateIndex,
724
duplicate;
725
726
if (objectOrArray) {
727
duplicateIndex = state.duplicates.indexOf(object);
728
duplicate = duplicateIndex !== -1;
729
}
730
731
if (duplicate && state.usedDuplicates[duplicateIndex]) {
732
state.dump = '*ref_' + duplicateIndex;
733
} else {
734
if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) {
735
state.usedDuplicates[duplicateIndex] = true;
736
}
737
if ('[object Object]' === type) {
738
if (block && (0 !== Object.keys(state.dump).length)) {
739
writeBlockMapping(state, level, state.dump, compact);
740
if (duplicate) {
741
state.dump = '&ref_' + duplicateIndex + (0 === level ? '\n' : '') + state.dump;
742
}
743
} else {
744
writeFlowMapping(state, level, state.dump);
745
if (duplicate) {
746
state.dump = '&ref_' + duplicateIndex + ' ' + state.dump;
747
}
748
}
749
} else if ('[object Array]' === type) {
750
if (block && (0 !== state.dump.length)) {
751
writeBlockSequence(state, level, state.dump, compact);
752
if (duplicate) {
753
state.dump = '&ref_' + duplicateIndex + (0 === level ? '\n' : '') + state.dump;
754
}
755
} else {
756
writeFlowSequence(state, level, state.dump);
757
if (duplicate) {
758
state.dump = '&ref_' + duplicateIndex + ' ' + state.dump;
759
}
760
}
761
} else if ('[object String]' === type) {
762
if ('?' !== state.tag) {
763
writeScalar(state, state.dump, level);
764
}
765
} else {
766
if (state.skipInvalid) {
767
return false;
768
}
769
throw new YAMLException('unacceptable kind of an object to dump ' + type);
770
}
771
772
if (null !== state.tag && '?' !== state.tag) {
773
state.dump = '!<' + state.tag + '> ' + state.dump;
774
}
775
}
776
777
return true;
778
}
779
780
function getDuplicateReferences(object, state) {
781
var objects = [],
782
duplicatesIndexes = [],
783
index,
784
length;
785
786
inspectNode(object, objects, duplicatesIndexes);
787
788
for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) {
789
state.duplicates.push(objects[duplicatesIndexes[index]]);
790
}
791
state.usedDuplicates = new Array(length);
792
}
793
794
function inspectNode(object, objects, duplicatesIndexes) {
795
var type = _toString.call(object),
796
objectKeyList,
797
index,
798
length;
799
800
if (null !== object && 'object' === typeof object) {
801
index = objects.indexOf(object);
802
if (-1 !== index) {
803
if (-1 === duplicatesIndexes.indexOf(index)) {
804
duplicatesIndexes.push(index);
805
}
806
} else {
807
objects.push(object);
808
809
if (Array.isArray(object)) {
810
for (index = 0, length = object.length; index < length; index += 1) {
811
inspectNode(object[index], objects, duplicatesIndexes);
812
}
813
} else {
814
objectKeyList = Object.keys(object);
815
816
for (index = 0, length = objectKeyList.length; index < length; index += 1) {
817
inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes);
818
}
819
}
820
}
821
}
822
}
823
824
function dump(input, options) {
825
options = options || {};
826
827
var state = new State(options);
828
829
getDuplicateReferences(input, state);
830
831
if (writeNode(state, 0, input, true, true)) {
832
return state.dump + '\n';
833
}
834
return '';
835
}
836
837
function safeDump(input, options) {
838
return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
839
}
840
841
module.exports.dump = dump;
842
module.exports.safeDump = safeDump;
843
844