• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

json5 / json5 / 473

pending completion
473

push

travis-ci-com

jordanbtucker
1.0.2

388 of 388 branches covered (100.0%)

Branch coverage included in aggregate %.

614 of 614 relevant lines covered (100.0%)

144.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/parse.js
1
import * as util from './util'
2

3
let source
4
let parseState
5
let stack
6
let pos
7
let line
8
let column
9
let token
10
let key
11
let root
12

13
export default function parse (text, reviver) {
14
    source = String(text)
294✔
15
    parseState = 'start'
294✔
16
    stack = []
294✔
17
    pos = 0
294✔
18
    line = 1
294✔
19
    column = 0
294✔
20
    token = undefined
294✔
21
    key = undefined
294✔
22
    root = undefined
294✔
23

24
    do {
294✔
25
        token = lex()
1,305✔
26

27
        // This code is unreachable.
28
        // if (!parseStates[parseState]) {
29
        //     throw invalidParseState()
30
        // }
31

32
        parseStates[parseState]()
1,191✔
33
    } while (token.type !== 'eof')
34

35
    if (typeof reviver === 'function') {
156✔
36
        return internalize({'': root}, '', reviver)
24✔
37
    }
38

39
    return root
132✔
40
}
41

42
function internalize (holder, name, reviver) {
43
    const value = holder[name]
81✔
44
    if (value != null && typeof value === 'object') {
81✔
45
        if (Array.isArray(value)) {
30✔
46
            for (let i = 0; i < value.length; i++) {
12✔
47
                const key = String(i)
33✔
48
                const replacement = internalize(value, key, reviver)
33✔
49
                if (replacement === undefined) {
33✔
50
                    delete value[key]
3✔
51
                } else {
52
                    Object.defineProperty(value, key, {
30✔
53
                        value: replacement,
54
                        writable: true,
55
                        enumerable: true,
56
                        configurable: true,
57
                    })
58
                }
59
            }
60
        } else {
61
            for (const key in value) {
18✔
62
                const replacement = internalize(value, key, reviver)
24✔
63
                if (replacement === undefined) {
24✔
64
                    delete value[key]
3✔
65
                } else {
66
                    Object.defineProperty(value, key, {
21✔
67
                        value: replacement,
68
                        writable: true,
69
                        enumerable: true,
70
                        configurable: true,
71
                    })
72
                }
73
            }
74
        }
75
    }
76

77
    return reviver.call(holder, name, value)
81✔
78
}
79

80
let lexState
81
let buffer
82
let doubleQuote
83
let sign
84
let c
85

86
function lex () {
87
    lexState = 'default'
1,305✔
88
    buffer = ''
1,305✔
89
    doubleQuote = false
1,305✔
90
    sign = 1
1,305✔
91

92
    for (;;) {
1,305✔
93
        c = peek()
2,790✔
94

95
        // This code is unreachable.
96
        // if (!lexStates[lexState]) {
97
        //     throw invalidLexState(lexState)
98
        // }
99

100
        const token = lexStates[lexState]()
2,790✔
101
        if (token) {
2,676✔
102
            return token
1,191✔
103
        }
104
    }
105
}
106

107
function peek () {
108
    if (source[pos]) {
5,481✔
109
        return String.fromCodePoint(source.codePointAt(pos))
5,085✔
110
    }
111
}
112

113
function read () {
114
    const c = peek()
2,358✔
115

116
    if (c === '\n') {
2,358✔
117
        line++
42✔
118
        column = 0
42✔
119
    } else if (c) {
2,316✔
120
        column += c.length
2,124✔
121
    } else {
122
        column++
192✔
123
    }
124

125
    if (c) {
2,358✔
126
        pos += c.length
2,166✔
127
    }
128

129
    return c
2,358✔
130
}
131

132
const lexStates = {
33✔
133
    default () {
134
        switch (c) {
1,443✔
135
        case '\t':
136
        case '\v':
137
        case '\f':
138
        case ' ':
139
        case '\u00A0':
140
        case '\uFEFF':
141
        case '\n':
142
        case '\r':
143
        case '\u2028':
144
        case '\u2029':
145
            read()
129✔
146
            return
129✔
147

148
        case '/':
149
            read()
21✔
150
            lexState = 'comment'
21✔
151
            return
21✔
152

153
        case undefined:
154
            read()
174✔
155
            return newToken('eof')
174✔
156
        }
157

158
        if (util.isSpaceSeparator(c)) {
1,119✔
159
            read()
3✔
160
            return
3✔
161
        }
162

163
        // This code is unreachable.
164
        // if (!lexStates[parseState]) {
165
        //     throw invalidLexState(parseState)
166
        // }
167

168
        return lexStates[parseState]()
1,116✔
169
    },
170

171
    comment () {
172
        switch (c) {
21✔
173
        case '*':
174
            read()
9✔
175
            lexState = 'multiLineComment'
9✔
176
            return
9✔
177

178
        case '/':
179
            read()
9✔
180
            lexState = 'singleLineComment'
9✔
181
            return
9✔
182
        }
183

184
        throw invalidChar(read())
3✔
185
    },
186

187
    multiLineComment () {
188
        switch (c) {
36✔
189
        case '*':
190
            read()
9✔
191
            lexState = 'multiLineCommentAsterisk'
9✔
192
            return
9✔
193

194
        case undefined:
195
            throw invalidChar(read())
3✔
196
        }
197

198
        read()
24✔
199
    },
200

201
    multiLineCommentAsterisk () {
202
        switch (c) {
12✔
203
        case '*':
204
            read()
3✔
205
            return
3✔
206

207
        case '/':
208
            read()
3✔
209
            lexState = 'default'
3✔
210
            return
3✔
211

212
        case undefined:
213
            throw invalidChar(read())
3✔
214
        }
215

216
        read()
3✔
217
        lexState = 'multiLineComment'
3✔
218
    },
219

220
    singleLineComment () {
221
        switch (c) {
54✔
222
        case '\n':
223
        case '\r':
224
        case '\u2028':
225
        case '\u2029':
226
            read()
3✔
227
            lexState = 'default'
3✔
228
            return
3✔
229

230
        case undefined:
231
            read()
6✔
232
            return newToken('eof')
6✔
233
        }
234

235
        read()
45✔
236
    },
237

238
    value () {
239
        switch (c) {
384✔
240
        case '{':
241
        case '[':
242
            return newToken('punctuator', read())
15✔
243

244
        case 'n':
245
            read()
3✔
246
            literal('ull')
3✔
247
            return newToken('null', null)
3✔
248

249
        case 't':
250
            read()
6✔
251
            literal('rue')
6✔
252
            return newToken('boolean', true)
3✔
253

254
        case 'f':
255
            read()
3✔
256
            literal('alse')
3✔
257
            return newToken('boolean', false)
3✔
258

259
        case '-':
260
        case '+':
261
            if (read() === '-') {
21✔
262
                sign = -1
18✔
263
            }
264

265
            lexState = 'sign'
21✔
266
            return
21✔
267

268
        case '.':
269
            buffer = read()
9✔
270
            lexState = 'decimalPointLeading'
9✔
271
            return
9✔
272

273
        case '0':
274
            buffer = read()
33✔
275
            lexState = 'zero'
33✔
276
            return
33✔
277

278
        case '1':
279
        case '2':
280
        case '3':
281
        case '4':
282
        case '5':
283
        case '6':
284
        case '7':
285
        case '8':
286
        case '9':
287
            buffer = read()
210✔
288
            lexState = 'decimalInteger'
210✔
289
            return
210✔
290

291
        case 'I':
292
            read()
3✔
293
            literal('nfinity')
3✔
294
            return newToken('numeric', Infinity)
3✔
295

296
        case 'N':
297
            read()
3✔
298
            literal('aN')
3✔
299
            return newToken('numeric', NaN)
3✔
300

301
        case '"':
302
        case "'":
303
            doubleQuote = (read() === '"')
66✔
304
            buffer = ''
66✔
305
            lexState = 'string'
66✔
306
            return
66✔
307
        }
308

309
        throw invalidChar(read())
12✔
310
    },
311

312
    identifierNameStartEscape () {
313
        if (c !== 'u') {
15✔
314
            throw invalidChar(read())
3✔
315
        }
316

317
        read()
12✔
318
        const u = unicodeEscape()
12✔
319
        switch (u) {
12✔
320
        case '$':
321
        case '_':
322
            break
6✔
323

324
        default:
325
            if (!util.isIdStartChar(u)) {
6✔
326
                throw invalidIdentifier()
3✔
327
            }
328

329
            break
3✔
330
        }
331

332
        buffer += u
9✔
333
        lexState = 'identifierName'
9✔
334
    },
335

336
    identifierName () {
337
        switch (c) {
177✔
338
        case '$':
339
        case '_':
340
        case '\u200C':
341
        case '\u200D':
342
            buffer += read()
9✔
343
            return
9✔
344

345
        case '\\':
346
            read()
15✔
347
            lexState = 'identifierNameEscape'
15✔
348
            return
15✔
349
        }
350

351
        if (util.isIdContinueChar(c)) {
153✔
352
            buffer += read()
30✔
353
            return
30✔
354
        }
355

356
        return newToken('identifier', buffer)
123✔
357
    },
358

359
    identifierNameEscape () {
360
        if (c !== 'u') {
15✔
361
            throw invalidChar(read())
3✔
362
        }
363

364
        read()
12✔
365
        const u = unicodeEscape()
12✔
366
        switch (u) {
12✔
367
        case '$':
368
        case '_':
369
        case '\u200C':
370
        case '\u200D':
371
            break
6✔
372

373
        default:
374
            if (!util.isIdContinueChar(u)) {
6✔
375
                throw invalidIdentifier()
3✔
376
            }
377

378
            break
3✔
379
        }
380

381
        buffer += u
9✔
382
        lexState = 'identifierName'
9✔
383
    },
384

385
    sign () {
386
        switch (c) {
21✔
387
        case '.':
388
            buffer = read()
3✔
389
            lexState = 'decimalPointLeading'
3✔
390
            return
3✔
391

392
        case '0':
393
            buffer = read()
3✔
394
            lexState = 'zero'
3✔
395
            return
3✔
396

397
        case '1':
398
        case '2':
399
        case '3':
400
        case '4':
401
        case '5':
402
        case '6':
403
        case '7':
404
        case '8':
405
        case '9':
406
            buffer = read()
6✔
407
            lexState = 'decimalInteger'
6✔
408
            return
6✔
409

410
        case 'I':
411
            read()
3✔
412
            literal('nfinity')
3✔
413
            return newToken('numeric', sign * Infinity)
3✔
414

415
        case 'N':
416
            read()
3✔
417
            literal('aN')
3✔
418
            return newToken('numeric', NaN)
3✔
419
        }
420

421
        throw invalidChar(read())
3✔
422
    },
423

424
    zero () {
425
        switch (c) {
36✔
426
        case '.':
427
            buffer += read()
3✔
428
            lexState = 'decimalPoint'
3✔
429
            return
3✔
430

431
        case 'e':
432
        case 'E':
433
            buffer += read()
3✔
434
            lexState = 'decimalExponent'
3✔
435
            return
3✔
436

437
        case 'x':
438
        case 'X':
439
            buffer += read()
15✔
440
            lexState = 'hexadecimal'
15✔
441
            return
15✔
442
        }
443

444
        return newToken('numeric', sign * 0)
15✔
445
    },
446

447
    decimalInteger () {
448
        switch (c) {
234✔
449
        case '.':
450
            buffer += read()
12✔
451
            lexState = 'decimalPoint'
12✔
452
            return
12✔
453

454
        case 'e':
455
        case 'E':
456
            buffer += read()
21✔
457
            lexState = 'decimalExponent'
21✔
458
            return
21✔
459
        }
460

461
        if (util.isDigit(c)) {
201✔
462
            buffer += read()
18✔
463
            return
18✔
464
        }
465

466
        return newToken('numeric', sign * Number(buffer))
183✔
467
    },
468

469
    decimalPointLeading () {
470
        if (util.isDigit(c)) {
12✔
471
            buffer += read()
9✔
472
            lexState = 'decimalFraction'
9✔
473
            return
9✔
474
        }
475

476
        throw invalidChar(read())
3✔
477
    },
478

479
    decimalPoint () {
480
        switch (c) {
15✔
481
        case 'e':
482
        case 'E':
483
            buffer += read()
3✔
484
            lexState = 'decimalExponent'
3✔
485
            return
3✔
486
        }
487

488
        if (util.isDigit(c)) {
12✔
489
            buffer += read()
9✔
490
            lexState = 'decimalFraction'
9✔
491
            return
9✔
492
        }
493

494
        return newToken('numeric', sign * Number(buffer))
3✔
495
    },
496

497
    decimalFraction () {
498
        switch (c) {
24✔
499
        case 'e':
500
        case 'E':
501
            buffer += read()
3✔
502
            lexState = 'decimalExponent'
3✔
503
            return
3✔
504
        }
505

506
        if (util.isDigit(c)) {
21✔
507
            buffer += read()
6✔
508
            return
6✔
509
        }
510

511
        return newToken('numeric', sign * Number(buffer))
15✔
512
    },
513

514
    decimalExponent () {
515
        switch (c) {
30✔
516
        case '+':
517
        case '-':
518
            buffer += read()
9✔
519
            lexState = 'decimalExponentSign'
9✔
520
            return
9✔
521
        }
522

523
        if (util.isDigit(c)) {
21✔
524
            buffer += read()
18✔
525
            lexState = 'decimalExponentInteger'
18✔
526
            return
18✔
527
        }
528

529
        throw invalidChar(read())
3✔
530
    },
531

532
    decimalExponentSign () {
533
        if (util.isDigit(c)) {
9✔
534
            buffer += read()
6✔
535
            lexState = 'decimalExponentInteger'
6✔
536
            return
6✔
537
        }
538

539
        throw invalidChar(read())
3✔
540
    },
541

542
    decimalExponentInteger () {
543
        if (util.isDigit(c)) {
27✔
544
            buffer += read()
3✔
545
            return
3✔
546
        }
547

548
        return newToken('numeric', sign * Number(buffer))
24✔
549
    },
550

551
    hexadecimal () {
552
        if (util.isHexDigit(c)) {
15✔
553
            buffer += read()
12✔
554
            lexState = 'hexadecimalInteger'
12✔
555
            return
12✔
556
        }
557

558
        throw invalidChar(read())
3✔
559
    },
560

561
    hexadecimalInteger () {
562
        if (util.isHexDigit(c)) {
21✔
563
            buffer += read()
9✔
564
            return
9✔
565
        }
566

567
        return newToken('numeric', sign * Number(buffer))
12✔
568
    },
569

570
    string () {
571
        switch (c) {
189✔
572
        case '\\':
573
            read()
93✔
574
            buffer += escape()
93✔
575
            return
51✔
576

577
        case '"':
578
            if (doubleQuote) {
15✔
579
                read()
12✔
580
                return newToken('string', buffer)
12✔
581
            }
582

583
            buffer += read()
3✔
584
            return
3✔
585

586
        case "'":
587
            if (!doubleQuote) {
18✔
588
                read()
15✔
589
                return newToken('string', buffer)
15✔
590
            }
591

592
            buffer += read()
3✔
593
            return
3✔
594

595
        case '\n':
596
        case '\r':
597
            throw invalidChar(read())
3✔
598

599
        case '\u2028':
600
        case '\u2029':
601
            separatorChar(c)
6✔
602
            break
6✔
603

604
        case undefined:
605
            throw invalidChar(read())
3✔
606
        }
607

608
        buffer += read()
57✔
609
    },
610

611
    start () {
612
        switch (c) {
279✔
613
        case '{':
614
        case '[':
615
            return newToken('punctuator', read())
168✔
616

617
        // This code is unreachable since the default lexState handles eof.
618
        // case undefined:
619
        //     return newToken('eof')
620
        }
621

622
        lexState = 'value'
111✔
623
    },
624

625
    beforePropertyName () {
626
        switch (c) {
162✔
627
        case '$':
628
        case '_':
629
            buffer = read()
6✔
630
            lexState = 'identifierName'
6✔
631
            return
6✔
632

633
        case '\\':
634
            read()
15✔
635
            lexState = 'identifierNameStartEscape'
15✔
636
            return
15✔
637

638
        case '}':
639
            return newToken('punctuator', read())
15✔
640

641
        case '"':
642
        case "'":
643
            doubleQuote = (read() === '"')
9✔
644
            lexState = 'string'
9✔
645
            return
9✔
646
        }
647

648
        if (util.isIdStartChar(c)) {
117✔
649
            buffer += read()
114✔
650
            lexState = 'identifierName'
114✔
651
            return
114✔
652
        }
653

654
        throw invalidChar(read())
3✔
655
    },
656

657
    afterPropertyName () {
658
        if (c === ':') {
129✔
659
            return newToken('punctuator', read())
126✔
660
        }
661

662
        throw invalidChar(read())
3✔
663
    },
664

665
    beforePropertyValue () {
666
        lexState = 'value'
123✔
667
    },
668

669
    afterPropertyValue () {
670
        switch (c) {
120✔
671
        case ',':
672
        case '}':
673
            return newToken('punctuator', read())
117✔
674
        }
675

676
        throw invalidChar(read())
3✔
677
    },
678

679
    beforeArrayValue () {
680
        if (c === ']') {
153✔
681
            return newToken('punctuator', read())
3✔
682
        }
683

684
        lexState = 'value'
150✔
685
    },
686

687
    afterArrayValue () {
688
        switch (c) {
147✔
689
        case ',':
690
        case ']':
691
            return newToken('punctuator', read())
144✔
692
        }
693

694
        throw invalidChar(read())
3✔
695
    },
696

697
    end () {
698
        // This code is unreachable since it's handled by the default lexState.
699
        // if (c === undefined) {
700
        //     read()
701
        //     return newToken('eof')
702
        // }
703

704
        throw invalidChar(read())
3✔
705
    },
706
}
707

708
function newToken (type, value) {
709
    return {
1,191✔
710
        type,
711
        value,
712
        line,
713
        column,
714
    }
715
}
716

717
function literal (s) {
718
    for (const c of s) {
24✔
719
        const p = peek()
93✔
720

721
        if (p !== c) {
93✔
722
            throw invalidChar(read())
3✔
723
        }
724

725
        read()
90✔
726
    }
727
}
728

729
function escape () {
730
    const c = peek()
93✔
731
    switch (c) {
93✔
732
    case 'b':
733
        read()
3✔
734
        return '\b'
3✔
735

736
    case 'f':
737
        read()
3✔
738
        return '\f'
3✔
739

740
    case 'n':
741
        read()
3✔
742
        return '\n'
3✔
743

744
    case 'r':
745
        read()
3✔
746
        return '\r'
3✔
747

748
    case 't':
749
        read()
3✔
750
        return '\t'
3✔
751

752
    case 'v':
753
        read()
3✔
754
        return '\v'
3✔
755

756
    case '0':
757
        read()
6✔
758
        if (util.isDigit(peek())) {
6✔
759
            throw invalidChar(read())
3✔
760
        }
761

762
        return '\0'
3✔
763

764
    case 'x':
765
        read()
9✔
766
        return hexEscape()
9✔
767

768
    case 'u':
769
        read()
6✔
770
        return unicodeEscape()
6✔
771

772
    case '\n':
773
    case '\u2028':
774
    case '\u2029':
775
        read()
9✔
776
        return ''
9✔
777

778
    case '\r':
779
        read()
6✔
780
        if (peek() === '\n') {
6✔
781
            read()
3✔
782
        }
783

784
        return ''
6✔
785

786
    case '1':
787
    case '2':
788
    case '3':
789
    case '4':
790
    case '5':
791
    case '6':
792
    case '7':
793
    case '8':
794
    case '9':
795
        throw invalidChar(read())
27✔
796

797
    case undefined:
798
        throw invalidChar(read())
3✔
799
    }
800

801
    return read()
9✔
802
}
803

804
function hexEscape () {
805
    let buffer = ''
9✔
806
    let c = peek()
9✔
807

808
    if (!util.isHexDigit(c)) {
9✔
809
        throw invalidChar(read())
3✔
810
    }
811

812
    buffer += read()
6✔
813

814
    c = peek()
6✔
815
    if (!util.isHexDigit(c)) {
6✔
816
        throw invalidChar(read())
3✔
817
    }
818

819
    buffer += read()
3✔
820

821
    return String.fromCodePoint(parseInt(buffer, 16))
3✔
822
}
823

824
function unicodeEscape () {
825
    let buffer = ''
30✔
826
    let count = 4
30✔
827

828
    while (count-- > 0) {
30✔
829
        const c = peek()
120✔
830
        if (!util.isHexDigit(c)) {
120✔
831
            throw invalidChar(read())
3✔
832
        }
833

834
        buffer += read()
117✔
835
    }
836

837
    return String.fromCodePoint(parseInt(buffer, 16))
27✔
838
}
839

840
const parseStates = {
33✔
841
    start () {
842
        if (token.type === 'eof') {
207✔
843
            throw invalidEOF()
6✔
844
        }
845

846
        push()
201✔
847
    },
848

849
    beforePropertyName () {
850
        switch (token.type) {
150✔
851
        case 'identifier':
852
        case 'string':
853
            key = token.value
132✔
854
            parseState = 'afterPropertyName'
132✔
855
            return
132✔
856

857
        case 'punctuator':
858
            // This code is unreachable since it's handled by the lexState.
859
            // if (token.value !== '}') {
860
            //     throw invalidToken()
861
            // }
862

863
            pop()
15✔
864
            return
15✔
865

866
        case 'eof':
867
            throw invalidEOF()
3✔
868
        }
869

870
        // This code is unreachable since it's handled by the lexState.
871
        // throw invalidToken()
872
    },
873

874
    afterPropertyName () {
875
        // This code is unreachable since it's handled by the lexState.
876
        // if (token.type !== 'punctuator' || token.value !== ':') {
877
        //     throw invalidToken()
878
        // }
879

880
        if (token.type === 'eof') {
129✔
881
            throw invalidEOF()
3✔
882
        }
883

884
        parseState = 'beforePropertyValue'
126✔
885
    },
886

887
    beforePropertyValue () {
888
        if (token.type === 'eof') {
126✔
889
            throw invalidEOF()
3✔
890
        }
891

892
        push()
123✔
893
    },
894

895
    beforeArrayValue () {
896
        if (token.type === 'eof') {
156✔
897
            throw invalidEOF()
3✔
898
        }
899

900
        if (token.type === 'punctuator' && token.value === ']') {
153✔
901
            pop()
3✔
902
            return
3✔
903
        }
904

905
        push()
150✔
906
    },
907

908
    afterPropertyValue () {
909
        // This code is unreachable since it's handled by the lexState.
910
        // if (token.type !== 'punctuator') {
911
        //     throw invalidToken()
912
        // }
913

914
        if (token.type === 'eof') {
120✔
915
            throw invalidEOF()
3✔
916
        }
917

918
        switch (token.value) {
117✔
919
        case ',':
920
            parseState = 'beforePropertyName'
45✔
921
            return
45✔
922

923
        case '}':
924
            pop()
72✔
925
        }
926

927
        // This code is unreachable since it's handled by the lexState.
928
        // throw invalidToken()
929
    },
930

931
    afterArrayValue () {
932
        // This code is unreachable since it's handled by the lexState.
933
        // if (token.type !== 'punctuator') {
934
        //     throw invalidToken()
935
        // }
936

937
        if (token.type === 'eof') {
147✔
938
            throw invalidEOF()
3✔
939
        }
940

941
        switch (token.value) {
144✔
942
        case ',':
943
            parseState = 'beforeArrayValue'
93✔
944
            return
93✔
945

946
        case ']':
947
            pop()
51✔
948
        }
949

950
        // This code is unreachable since it's handled by the lexState.
951
        // throw invalidToken()
952
    },
953

954
    end () {
955
        // This code is unreachable since it's handled by the lexState.
956
        // if (token.type !== 'eof') {
957
        //     throw invalidToken()
958
        // }
959
    },
960
}
961

962
function push () {
963
    let value
964

965
    switch (token.type) {
474✔
966
    case 'punctuator':
967
        switch (token.value) {
183✔
968
        case '{':
969
            value = {}
120✔
970
            break
120✔
971

972
        case '[':
973
            value = []
63✔
974
            break
63✔
975
        }
976

977
        break
183✔
978

979
    case 'null':
980
    case 'boolean':
981
    case 'numeric':
982
    case 'string':
983
        value = token.value
291✔
984
        break
291✔
985

986
    // This code is unreachable.
987
    // default:
988
    //     throw invalidToken()
989
    }
990

991
    if (root === undefined) {
474✔
992
        root = value
201✔
993
    } else {
994
        const parent = stack[stack.length - 1]
273✔
995
        if (Array.isArray(parent)) {
273✔
996
            parent.push(value)
150✔
997
        } else {
998
            Object.defineProperty(parent, key, {
123✔
999
                value,
1000
                writable: true,
1001
                enumerable: true,
1002
                configurable: true,
1003
            })
1004
        }
1005
    }
1006

1007
    if (value !== null && typeof value === 'object') {
474✔
1008
        stack.push(value)
183✔
1009

1010
        if (Array.isArray(value)) {
183✔
1011
            parseState = 'beforeArrayValue'
63✔
1012
        } else {
1013
            parseState = 'beforePropertyName'
120✔
1014
        }
1015
    } else {
1016
        const current = stack[stack.length - 1]
291✔
1017
        if (current == null) {
291✔
1018
            parseState = 'end'
33✔
1019
        } else if (Array.isArray(current)) {
258✔
1020
            parseState = 'afterArrayValue'
144✔
1021
        } else {
1022
            parseState = 'afterPropertyValue'
114✔
1023
        }
1024
    }
1025
}
1026

1027
function pop () {
1028
    stack.pop()
141✔
1029

1030
    const current = stack[stack.length - 1]
141✔
1031
    if (current == null) {
141✔
1032
        parseState = 'end'
126✔
1033
    } else if (Array.isArray(current)) {
15✔
1034
        parseState = 'afterArrayValue'
6✔
1035
    } else {
1036
        parseState = 'afterPropertyValue'
9✔
1037
    }
1038
}
1039

1040
// This code is unreachable.
1041
// function invalidParseState () {
1042
//     return new Error(`JSON5: invalid parse state '${parseState}'`)
1043
// }
1044

1045
// This code is unreachable.
1046
// function invalidLexState (state) {
1047
//     return new Error(`JSON5: invalid lex state '${state}'`)
1048
// }
1049

1050
function invalidChar (c) {
1051
    if (c === undefined) {
108✔
1052
        return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
12✔
1053
    }
1054

1055
    return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
96✔
1056
}
1057

1058
function invalidEOF () {
1059
    return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
24✔
1060
}
1061

1062
// This code is unreachable.
1063
// function invalidToken () {
1064
//     if (token.type === 'eof') {
1065
//         return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
1066
//     }
1067

1068
//     const c = String.fromCodePoint(token.value.codePointAt(0))
1069
//     return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
1070
// }
1071

1072
function invalidIdentifier () {
1073
    column -= 5
6✔
1074
    return syntaxError(`JSON5: invalid identifier character at ${line}:${column}`)
6✔
1075
}
1076

1077
function separatorChar (c) {
1078
    console.warn(`JSON5: '${c}' is not valid ECMAScript; consider escaping`)
6✔
1079
}
1080

1081
function formatChar (c) {
1082
    const replacements = {
96✔
1083
        "'": "\\'",
1084
        '"': '\\"',
1085
        '\\': '\\\\',
1086
        '\b': '\\b',
1087
        '\f': '\\f',
1088
        '\n': '\\n',
1089
        '\r': '\\r',
1090
        '\t': '\\t',
1091
        '\v': '\\v',
1092
        '\0': '\\0',
1093
        '\u2028': '\\u2028',
1094
        '\u2029': '\\u2029',
1095
    }
1096

1097
    if (replacements[c]) {
96✔
1098
        return replacements[c]
3✔
1099
    }
1100

1101
    if (c < ' ') {
93✔
1102
        const hexString = c.charCodeAt(0).toString(16)
3✔
1103
        return '\\x' + ('00' + hexString).substring(hexString.length)
3✔
1104
    }
1105

1106
    return c
90✔
1107
}
1108

1109
function syntaxError (message) {
1110
    const err = new SyntaxError(message)
138✔
1111
    err.lineNumber = line
138✔
1112
    err.columnNumber = column
138✔
1113
    return err
138✔
1114
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc