fast-json-stringify 4.1.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/test/ref.test.js CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const clone = require('rfdc')({ proto: true })
4
+
3
5
  const test = require('tap').test
4
6
  const build = require('..')
5
7
 
@@ -431,10 +433,215 @@ test('ref external - plain name fragment', (t) => {
431
433
  type: 'object',
432
434
  properties: {
433
435
  first: {
434
- $ref: '#first-schema'
436
+ $ref: 'first#first-schema'
437
+ },
438
+ second: {
439
+ $ref: 'second#second-schema'
440
+ }
441
+ }
442
+ }
443
+
444
+ const object = {
445
+ first: {
446
+ str: 'test'
447
+ },
448
+ second: {
449
+ int: 42
450
+ }
451
+ }
452
+
453
+ const stringify = build(schema, { schema: externalSchema })
454
+ const output = stringify(object)
455
+
456
+ JSON.parse(output)
457
+ t.pass()
458
+
459
+ t.equal(output, '{"first":{"str":"test"},"second":{"int":42}}')
460
+ })
461
+
462
+ test('external reference to $id', (t) => {
463
+ t.plan(2)
464
+
465
+ const externalSchema = {
466
+ first: {
467
+ $id: 'external-reference',
468
+ type: 'object',
469
+ properties: {
470
+ str: {
471
+ type: 'string'
472
+ }
473
+ }
474
+ }
475
+ }
476
+
477
+ const schema = {
478
+ type: 'object',
479
+ properties: {
480
+ first: {
481
+ $ref: 'external-reference'
482
+ }
483
+ }
484
+ }
485
+
486
+ const object = { first: { str: 'test' } }
487
+
488
+ const stringify = build(schema, { schema: externalSchema })
489
+ const output = stringify(object)
490
+
491
+ JSON.parse(output)
492
+ t.pass()
493
+
494
+ t.equal(output, '{"first":{"str":"test"}}')
495
+ })
496
+
497
+ test('external reference to key#id', (t) => {
498
+ t.plan(2)
499
+
500
+ const externalSchema = {
501
+ first: {
502
+ $id: '#external-reference',
503
+ type: 'object',
504
+ properties: {
505
+ str: {
506
+ type: 'string'
507
+ }
508
+ }
509
+ }
510
+ }
511
+
512
+ const schema = {
513
+ type: 'object',
514
+ properties: {
515
+ first: {
516
+ $ref: 'first#external-reference'
517
+ }
518
+ }
519
+ }
520
+
521
+ const object = { first: { str: 'test' } }
522
+
523
+ const stringify = build(schema, { schema: externalSchema })
524
+ const output = stringify(object)
525
+
526
+ JSON.parse(output)
527
+ t.pass()
528
+
529
+ t.equal(output, '{"first":{"str":"test"}}')
530
+ })
531
+
532
+ test('external and inner reference', (t) => {
533
+ t.plan(2)
534
+
535
+ const externalSchema = {
536
+ first: {
537
+ $id: 'reference',
538
+ $ref: '#reference',
539
+ definitions: {
540
+ inner: {
541
+ $id: '#reference',
542
+ type: 'object',
543
+ properties: {
544
+ str: {
545
+ type: 'string'
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+ }
552
+
553
+ const schema = {
554
+ type: 'object',
555
+ properties: {
556
+ first: {
557
+ $ref: 'reference'
558
+ }
559
+ }
560
+ }
561
+
562
+ const object = { first: { str: 'test' } }
563
+
564
+ const stringify = build(schema, { schema: externalSchema })
565
+ const output = stringify(object)
566
+
567
+ JSON.parse(output)
568
+ t.pass()
569
+
570
+ t.equal(output, '{"first":{"str":"test"}}')
571
+ })
572
+
573
+ test('external reference to key', (t) => {
574
+ t.plan(2)
575
+
576
+ const externalSchema = {
577
+ first: {
578
+ $id: 'external-reference',
579
+ type: 'object',
580
+ properties: {
581
+ str: {
582
+ type: 'string'
583
+ }
584
+ }
585
+ }
586
+ }
587
+
588
+ const schema = {
589
+ type: 'object',
590
+ properties: {
591
+ first: {
592
+ $ref: 'external-reference'
593
+ }
594
+ }
595
+ }
596
+
597
+ const object = { first: { str: 'test' } }
598
+
599
+ const stringify = build(schema, { schema: externalSchema })
600
+ const output = stringify(object)
601
+
602
+ JSON.parse(output)
603
+ t.pass()
604
+
605
+ t.equal(output, '{"first":{"str":"test"}}')
606
+ })
607
+
608
+ test('ref external - plain name fragment', (t) => {
609
+ t.plan(2)
610
+
611
+ const externalSchema = {
612
+ first: {
613
+ $id: 'first-schema',
614
+ type: 'object',
615
+ properties: {
616
+ str: {
617
+ type: 'string'
618
+ }
619
+ }
620
+ },
621
+ second: {
622
+ definitions: {
623
+ second: {
624
+ $id: 'second-schema',
625
+ type: 'object',
626
+ properties: {
627
+ int: {
628
+ type: 'integer'
629
+ }
630
+ }
631
+ }
632
+ }
633
+ }
634
+ }
635
+
636
+ const schema = {
637
+ title: 'object with $ref to external plain name fragment',
638
+ type: 'object',
639
+ properties: {
640
+ first: {
641
+ $ref: 'first-schema'
435
642
  },
436
643
  second: {
437
- $ref: '#second-schema'
644
+ $ref: 'second-schema'
438
645
  }
439
646
  }
440
647
  }
@@ -503,7 +710,7 @@ test('ref external - duplicate plain name fragment', (t) => {
503
710
  $ref: 'external#duplicateSchema'
504
711
  },
505
712
  other: {
506
- $ref: '#otherSchema'
713
+ $ref: 'other#otherSchema'
507
714
  }
508
715
  }
509
716
  }
@@ -893,7 +1100,7 @@ test('ref in root external multiple times', (t) => {
893
1100
  const schema = {
894
1101
  title: 'object with $ref in root schema',
895
1102
  type: 'object',
896
- $ref: 'numbers#/definitions/num'
1103
+ $ref: 'numbers'
897
1104
  }
898
1105
 
899
1106
  const object = { int: 42 }
@@ -978,32 +1185,6 @@ test('ref to nested ref definition', (t) => {
978
1185
  t.equal(output, '{"foo":"foo"}')
979
1186
  })
980
1187
 
981
- test('ref in definition with exact match', (t) => {
982
- t.plan(2)
983
-
984
- const externalSchema = {
985
- '#/definitions/foo': {
986
- type: 'string'
987
- }
988
- }
989
-
990
- const schema = {
991
- type: 'object',
992
- properties: {
993
- foo: { $ref: '#/definitions/foo' }
994
- }
995
- }
996
-
997
- const object = { foo: 'foo' }
998
- const stringify = build(schema, { schema: externalSchema })
999
- const output = stringify(object)
1000
-
1001
- JSON.parse(output)
1002
- t.pass()
1003
-
1004
- t.equal(output, '{"foo":"foo"}')
1005
- })
1006
-
1007
1188
  test('Bad key', t => {
1008
1189
  t.test('Find match', t => {
1009
1190
  t.plan(1)
@@ -1026,7 +1207,7 @@ test('Bad key', t => {
1026
1207
  })
1027
1208
  t.fail('Should throw')
1028
1209
  } catch (err) {
1029
- t.equal(err.message, 'Cannot find reference "porjectId", did you mean "projectId"?')
1210
+ t.equal(err.message, 'Cannot find reference "#/definitions/porjectId"')
1030
1211
  }
1031
1212
  })
1032
1213
 
@@ -1051,7 +1232,7 @@ test('Bad key', t => {
1051
1232
  })
1052
1233
  t.fail('Should throw')
1053
1234
  } catch (err) {
1054
- t.equal(err.message, 'Cannot find reference "foobar"')
1235
+ t.equal(err.message, 'Cannot find reference "#/definitions/foobar"')
1055
1236
  }
1056
1237
  })
1057
1238
 
@@ -1081,7 +1262,7 @@ test('Bad key', t => {
1081
1262
  })
1082
1263
  t.fail('Should throw')
1083
1264
  } catch (err) {
1084
- t.equal(err.message, 'Cannot find reference "porjectId", did you mean "projectId"?')
1265
+ t.equal(err.message, 'Cannot find reference "external#/definitions/porjectId"')
1085
1266
  }
1086
1267
  })
1087
1268
 
@@ -1111,7 +1292,7 @@ test('Bad key', t => {
1111
1292
  })
1112
1293
  t.fail('Should throw')
1113
1294
  } catch (err) {
1114
- t.equal(err.message, 'Cannot find reference "foobar"')
1295
+ t.equal(err.message, 'Cannot find reference "external#/definitions/foobar"')
1115
1296
  }
1116
1297
  })
1117
1298
 
@@ -1141,7 +1322,7 @@ test('Bad key', t => {
1141
1322
  })
1142
1323
  t.fail('Should throw')
1143
1324
  } catch (err) {
1144
- t.equal(err.message, 'Cannot find reference "deifnitions", did you mean "definitions"?')
1325
+ t.equal(err.message, 'Cannot find reference "external#/deifnitions/projectId"')
1145
1326
  }
1146
1327
  })
1147
1328
 
@@ -1166,7 +1347,7 @@ test('Bad key', t => {
1166
1347
  })
1167
1348
  t.fail('Should throw')
1168
1349
  } catch (err) {
1169
- t.equal(err.message, 'Cannot find reference "deifnitions", did you mean "definitions"?')
1350
+ t.equal(err.message, 'Cannot find reference "#/deifnitions/projectId"')
1170
1351
  }
1171
1352
  })
1172
1353
 
@@ -1196,7 +1377,7 @@ test('Bad key', t => {
1196
1377
  })
1197
1378
  t.fail('Should throw')
1198
1379
  } catch (err) {
1199
- t.equal(err.message, 'Cannot find reference "extrenal", did you mean "external"?')
1380
+ t.equal(err.message, 'Cannot find reference "extrenal#/definitions/projectId"')
1200
1381
  }
1201
1382
  })
1202
1383
 
@@ -1249,3 +1430,464 @@ test('Regression 2.5.2', t => {
1249
1430
 
1250
1431
  t.equal(output, '[{"field":"parent","sub":{"field":"joined"}}]')
1251
1432
  })
1433
+
1434
+ test('Reference through multiple definitions', (t) => {
1435
+ t.plan(2)
1436
+
1437
+ const schema = {
1438
+ $ref: '#/definitions/A',
1439
+ definitions: {
1440
+ A: {
1441
+ type: 'object',
1442
+ additionalProperties: false,
1443
+ properties: { a: { anyOf: [{ $ref: '#/definitions/B' }] } },
1444
+ required: ['a']
1445
+ },
1446
+ B: {
1447
+ type: 'object',
1448
+ properties: { b: { anyOf: [{ $ref: '#/definitions/C' }] } },
1449
+ required: ['b'],
1450
+ additionalProperties: false
1451
+ },
1452
+ C: {
1453
+ type: 'object',
1454
+ properties: { c: { type: 'string', const: 'd' } },
1455
+ required: ['c'],
1456
+ additionalProperties: false
1457
+ }
1458
+ }
1459
+ }
1460
+
1461
+ const object = { a: { b: { c: 'd' } } }
1462
+
1463
+ const stringify = build(schema)
1464
+ const output = stringify(object)
1465
+
1466
+ JSON.parse(output)
1467
+ t.pass()
1468
+
1469
+ t.equal(output, JSON.stringify(object))
1470
+ })
1471
+
1472
+ test('issue #350', (t) => {
1473
+ t.plan(2)
1474
+
1475
+ const schema = {
1476
+ title: 'Example Schema',
1477
+ type: 'object',
1478
+ properties: {
1479
+ firstName: { $ref: '#foo' },
1480
+ lastName: { $ref: '#foo' },
1481
+ nested: {
1482
+ type: 'object',
1483
+ properties: {
1484
+ firstName: { $ref: '#foo' },
1485
+ lastName: { $ref: '#foo' }
1486
+ }
1487
+ }
1488
+ },
1489
+ definitions: {
1490
+ foo: {
1491
+ $id: '#foo',
1492
+ type: 'string'
1493
+ }
1494
+ }
1495
+ }
1496
+
1497
+ const object = {
1498
+ firstName: 'Matteo',
1499
+ lastName: 'Collina',
1500
+ nested: {
1501
+ firstName: 'Matteo',
1502
+ lastName: 'Collina'
1503
+ }
1504
+ }
1505
+
1506
+ const stringify = build(schema)
1507
+ const output = stringify(object)
1508
+
1509
+ JSON.parse(output)
1510
+ t.pass()
1511
+
1512
+ t.equal(output, JSON.stringify(object))
1513
+ })
1514
+
1515
+ test('deep union type', (t) => {
1516
+ t.plan(1)
1517
+
1518
+ const stringify = build({
1519
+ schema: {
1520
+ type: 'array',
1521
+ items: {
1522
+ oneOf: [
1523
+ {
1524
+ $ref: 'components#/schemas/IDirectory'
1525
+ },
1526
+ {
1527
+ $ref: 'components#/schemas/IImageFile'
1528
+ },
1529
+ {
1530
+ $ref: 'components#/schemas/ITextFile'
1531
+ },
1532
+ {
1533
+ $ref: 'components#/schemas/IZipFile'
1534
+ }
1535
+ ]
1536
+ },
1537
+ nullable: false
1538
+ },
1539
+ components: {
1540
+ schemas: {
1541
+ IDirectory: {
1542
+ $id: 'IDirectory',
1543
+ $recursiveAnchor: true,
1544
+ type: 'object',
1545
+ properties: {
1546
+ children: {
1547
+ type: 'array',
1548
+ items: {
1549
+ oneOf: [
1550
+ {
1551
+ $recursiveRef: '#'
1552
+ },
1553
+ {
1554
+ $ref: 'components#/schemas/IImageFile'
1555
+ },
1556
+ {
1557
+ $ref: 'components#/schemas/ITextFile'
1558
+ },
1559
+ {
1560
+ $ref: 'components#/schemas/IZipFile'
1561
+ }
1562
+ ]
1563
+ },
1564
+ nullable: false
1565
+ },
1566
+ type: {
1567
+ type: 'string',
1568
+ nullable: false
1569
+ },
1570
+ id: {
1571
+ type: 'string',
1572
+ nullable: false
1573
+ },
1574
+ name: {
1575
+ type: 'string',
1576
+ nullable: false
1577
+ }
1578
+ },
1579
+ nullable: false,
1580
+ required: [
1581
+ 'children',
1582
+ 'type',
1583
+ 'id',
1584
+ 'name'
1585
+ ]
1586
+ },
1587
+ IImageFile: {
1588
+ $id: 'IImageFile',
1589
+ type: 'object',
1590
+ properties: {
1591
+ width: {
1592
+ type: 'number',
1593
+ nullable: false
1594
+ },
1595
+ height: {
1596
+ type: 'number',
1597
+ nullable: false
1598
+ },
1599
+ url: {
1600
+ type: 'string',
1601
+ nullable: false
1602
+ },
1603
+ extension: {
1604
+ type: 'string',
1605
+ nullable: false
1606
+ },
1607
+ size: {
1608
+ type: 'number',
1609
+ nullable: false
1610
+ },
1611
+ type: {
1612
+ type: 'string',
1613
+ nullable: false
1614
+ },
1615
+ id: {
1616
+ type: 'string',
1617
+ nullable: false
1618
+ },
1619
+ name: {
1620
+ type: 'string',
1621
+ nullable: false
1622
+ }
1623
+ },
1624
+ nullable: false,
1625
+ required: [
1626
+ 'width',
1627
+ 'height',
1628
+ 'url',
1629
+ 'extension',
1630
+ 'size',
1631
+ 'type',
1632
+ 'id',
1633
+ 'name'
1634
+ ]
1635
+ },
1636
+ ITextFile: {
1637
+ $id: 'ITextFile',
1638
+ type: 'object',
1639
+ properties: {
1640
+ content: {
1641
+ type: 'string',
1642
+ nullable: false
1643
+ },
1644
+ extension: {
1645
+ type: 'string',
1646
+ nullable: false
1647
+ },
1648
+ size: {
1649
+ type: 'number',
1650
+ nullable: false
1651
+ },
1652
+ type: {
1653
+ type: 'string',
1654
+ nullable: false
1655
+ },
1656
+ id: {
1657
+ type: 'string',
1658
+ nullable: false
1659
+ },
1660
+ name: {
1661
+ type: 'string',
1662
+ nullable: false
1663
+ }
1664
+ },
1665
+ nullable: false,
1666
+ required: [
1667
+ 'content',
1668
+ 'extension',
1669
+ 'size',
1670
+ 'type',
1671
+ 'id',
1672
+ 'name'
1673
+ ]
1674
+ },
1675
+ IZipFile: {
1676
+ $id: 'IZipFile',
1677
+ type: 'object',
1678
+ properties: {
1679
+ files: {
1680
+ type: 'number',
1681
+ nullable: false
1682
+ },
1683
+ extension: {
1684
+ type: 'string',
1685
+ nullable: false
1686
+ },
1687
+ size: {
1688
+ type: 'number',
1689
+ nullable: false
1690
+ },
1691
+ type: {
1692
+ type: 'string',
1693
+ nullable: false
1694
+ },
1695
+ id: {
1696
+ type: 'string',
1697
+ nullable: false
1698
+ },
1699
+ name: {
1700
+ type: 'string',
1701
+ nullable: false
1702
+ }
1703
+ },
1704
+ nullable: false,
1705
+ required: [
1706
+ 'files',
1707
+ 'extension',
1708
+ 'size',
1709
+ 'type',
1710
+ 'id',
1711
+ 'name'
1712
+ ]
1713
+ }
1714
+ }
1715
+ }
1716
+ })
1717
+
1718
+ const obj = [
1719
+ {
1720
+ type: 'directory',
1721
+ id: '7b1068a4-dd6e-474a-8d85-09a2d77639cb',
1722
+ name: 'ixcWGOKI',
1723
+ children: [
1724
+ {
1725
+ type: 'directory',
1726
+ id: '5883e17c-b207-46d4-ad2d-be72249711ce',
1727
+ name: 'vecQwFGS',
1728
+ children: []
1729
+ },
1730
+ {
1731
+ type: 'file',
1732
+ id: '670b6556-a610-4a48-8a16-9c2da97a0d18',
1733
+ name: 'eStFddzX',
1734
+ extension: 'jpg',
1735
+ size: 7,
1736
+ width: 300,
1737
+ height: 1200,
1738
+ url: 'https://github.com/samchon/typescript-json'
1739
+ },
1740
+ {
1741
+ type: 'file',
1742
+ id: '85dc796d-9593-4833-b1a1-addc8ebf74ea',
1743
+ name: 'kTdUfwRJ',
1744
+ extension: 'ts',
1745
+ size: 86,
1746
+ content: 'console.log("Hello world");'
1747
+ },
1748
+ {
1749
+ type: 'file',
1750
+ id: '8933c86a-7a1e-4d4a-b0a6-17d6896fdf89',
1751
+ name: 'NBPkefUG',
1752
+ extension: 'zip',
1753
+ size: 22,
1754
+ files: 20
1755
+ }
1756
+ ]
1757
+ }
1758
+ ]
1759
+ t.equal(JSON.stringify(obj), stringify(obj))
1760
+ })
1761
+
1762
+ test('ref with same id in properties', (t) => {
1763
+ t.plan(2)
1764
+
1765
+ const externalSchema = {
1766
+ ObjectId: {
1767
+ $id: 'ObjectId',
1768
+ type: 'string'
1769
+ },
1770
+ File: {
1771
+ $id: 'File',
1772
+ type: 'object',
1773
+ properties: {
1774
+ _id: { $ref: 'ObjectId' },
1775
+ name: { type: 'string' },
1776
+ owner: { $ref: 'ObjectId' }
1777
+ }
1778
+ }
1779
+ }
1780
+
1781
+ t.test('anyOf', (t) => {
1782
+ t.plan(1)
1783
+
1784
+ const schema = {
1785
+ $id: 'Article',
1786
+ type: 'object',
1787
+ properties: {
1788
+ _id: { $ref: 'ObjectId' },
1789
+ image: {
1790
+ anyOf: [
1791
+ { $ref: 'File' },
1792
+ { type: 'null' }
1793
+ ]
1794
+ }
1795
+ }
1796
+ }
1797
+
1798
+ const stringify = build(schema, { schema: externalSchema })
1799
+ const output = stringify({ _id: 'foo', image: { _id: 'bar', name: 'hello', owner: 'baz' } })
1800
+
1801
+ t.equal(output, '{"_id":"foo","image":{"_id":"bar","name":"hello","owner":"baz"}}')
1802
+ })
1803
+
1804
+ t.test('oneOf', (t) => {
1805
+ t.plan(1)
1806
+
1807
+ const schema = {
1808
+ $id: 'Article',
1809
+ type: 'object',
1810
+ properties: {
1811
+ _id: { $ref: 'ObjectId' },
1812
+ image: {
1813
+ oneOf: [
1814
+ { $ref: 'File' },
1815
+ { type: 'null' }
1816
+ ]
1817
+ }
1818
+ }
1819
+ }
1820
+
1821
+ const stringify = build(schema, { schema: externalSchema })
1822
+ const output = stringify({ _id: 'foo', image: { _id: 'bar', name: 'hello', owner: 'baz' } })
1823
+
1824
+ t.equal(output, '{"_id":"foo","image":{"_id":"bar","name":"hello","owner":"baz"}}')
1825
+ })
1826
+ })
1827
+
1828
+ test('Should not modify external schemas', (t) => {
1829
+ t.plan(2)
1830
+
1831
+ const externalSchema = {
1832
+ uuid: {
1833
+ format: 'uuid',
1834
+ $id: 'UUID',
1835
+ type: 'string'
1836
+ },
1837
+ Entity: {
1838
+ $id: 'Entity',
1839
+ type: 'object',
1840
+ properties: {
1841
+ id: { $ref: 'UUID' },
1842
+ id2: { $ref: 'UUID' }
1843
+ }
1844
+ }
1845
+ }
1846
+
1847
+ const options = { schema: externalSchema }
1848
+ const optionsClone = clone(options)
1849
+
1850
+ const stringify = build({ $ref: 'Entity' }, options)
1851
+
1852
+ const data = { id: 'a4e4c954-9f5f-443a-aa65-74d95732249a' }
1853
+ const output = stringify(data)
1854
+
1855
+ t.equal(output, JSON.stringify(data))
1856
+ t.same(options, optionsClone)
1857
+ })
1858
+
1859
+ test('input schema is not mutated', (t) => {
1860
+ t.plan(3)
1861
+
1862
+ const schema = {
1863
+ title: 'object with $ref',
1864
+ type: 'object',
1865
+ definitions: {
1866
+ def: { type: 'string' }
1867
+ },
1868
+ properties: {
1869
+ obj: {
1870
+ $ref: '#/definitions/def'
1871
+ }
1872
+ }
1873
+ }
1874
+
1875
+ const clonedSchema = JSON.parse(JSON.stringify(schema))
1876
+
1877
+ const object = {
1878
+ obj: 'test'
1879
+ }
1880
+
1881
+ const stringify = build(schema)
1882
+ const output = stringify(object)
1883
+
1884
+ try {
1885
+ JSON.parse(output)
1886
+ t.pass()
1887
+ } catch (e) {
1888
+ t.fail()
1889
+ }
1890
+
1891
+ t.equal(output, '{"obj":"test"}')
1892
+ t.same(schema, clonedSchema)
1893
+ })