@sap/cds-dk 10.2.0 → 10.2.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.
Files changed (90) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/bind.js +5 -4
  3. package/bin/completion/scripts/cds.fish +4 -3
  4. package/bin/completion/scripts/cds.ps1 +4 -4
  5. package/bin/completion/scripts/cds.sh +4 -4
  6. package/bin/completion/scripts/cds.zsh +4 -4
  7. package/bin/debug.js +3 -3
  8. package/bin/deploy/index.js +2 -2
  9. package/bin/deploy/to-hana/hana.js +1 -1
  10. package/bin/deploy/to-hana/hdiDeployUtil.js +25 -14
  11. package/bin/up.js +3 -3
  12. package/bin/version.js +1 -1
  13. package/bin/watch/vite-watch.js +12 -6
  14. package/lib/bind/shared.js +1 -1
  15. package/lib/init/index.js +1 -0
  16. package/lib/init/projectReader.js +3 -2
  17. package/lib/init/template/approuter/files/values.yaml.hbs +0 -9
  18. package/lib/init/template/approuter/files/xs-app.json.hbs +0 -22
  19. package/lib/init/template/approuter/index.js +8 -9
  20. package/lib/init/template/html5-repo/index.js +12 -0
  21. package/lib/init/template/react/files/vite.config.{{extension}}.hbs +2 -3
  22. package/lib/init/template/react/index.js +1 -3
  23. package/lib/init/template/sample/files/app/index.html.hbs +18 -0
  24. package/lib/init/template/sample/index.js +1 -0
  25. package/lib/init/template/vue/files/vite.config.{{extension}}.hbs +2 -3
  26. package/lib/init/template/vue/index.js +1 -3
  27. package/lib/mtx/push.js +7 -1
  28. package/node_modules/@cap-js/asyncapi/README.md +4 -14
  29. package/node_modules/@cap-js/asyncapi/cds-plugin.js +12 -0
  30. package/node_modules/@cap-js/asyncapi/index.js +3 -2
  31. package/node_modules/@cap-js/asyncapi/lib/compile/components/messages/index.js +4 -2
  32. package/node_modules/@cap-js/asyncapi/lib/compile/components/schemas/definition.js +11 -1
  33. package/node_modules/@cap-js/asyncapi/lib/compile/components/schemas/utils.js +16 -0
  34. package/node_modules/@cap-js/asyncapi/lib/compile/utils.js +4 -3
  35. package/node_modules/@cap-js/asyncapi/lib/import/importAsyncAPI.js +34 -0
  36. package/node_modules/@cap-js/asyncapi/lib/import/index.js +18 -0
  37. package/node_modules/@cap-js/asyncapi/lib/import/message.js +9 -0
  38. package/node_modules/@cap-js/asyncapi/lib/import/parserContext.js +368 -0
  39. package/node_modules/@cap-js/asyncapi/lib/import/utils.js +85 -0
  40. package/node_modules/@cap-js/asyncapi/package.json +89 -1
  41. package/node_modules/@sap/cds/CHANGELOG.md +10 -0
  42. package/node_modules/@sap/cds/app/index.js +1 -1
  43. package/node_modules/@sap/cds/lib/env/schemas/cds-package.js +0 -2
  44. package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +3 -3
  45. package/node_modules/@sap/cds/lib/env/schemas/index.js +4 -4
  46. package/node_modules/@sap/cds/lib/utils/cds-utils.js +21 -8
  47. package/node_modules/@sap/cds/libx/_runtime/messaging/common-utils/connections.js +45 -39
  48. package/node_modules/@sap/cds/libx/odata/ODataAdapter.js +1 -1
  49. package/node_modules/@sap/cds/libx/queue/TaskRunner.js +22 -5
  50. package/node_modules/@sap/cds/package.json +1 -1
  51. package/node_modules/@sap/cds-mtxs/CHANGELOG.md +8 -0
  52. package/node_modules/@sap/cds-mtxs/package.json +1 -1
  53. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +57 -41
  54. package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +27 -12
  55. package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +31 -25
  56. package/node_modules/body-parser/README.md +17 -13
  57. package/node_modules/body-parser/lib/read.js +74 -57
  58. package/node_modules/body-parser/lib/types/json.js +11 -11
  59. package/node_modules/body-parser/lib/types/urlencoded.js +5 -5
  60. package/node_modules/body-parser/lib/utils.js +0 -15
  61. package/node_modules/body-parser/package.json +7 -12
  62. package/node_modules/encodeurl/README.md +14 -0
  63. package/node_modules/encodeurl/index.js +5 -10
  64. package/node_modules/encodeurl/package.json +10 -6
  65. package/node_modules/on-finished/index.js +14 -2
  66. package/node_modules/on-finished/package.json +11 -7
  67. package/node_modules/qs/.editorconfig +1 -1
  68. package/node_modules/qs/CHANGELOG.md +87 -22
  69. package/node_modules/qs/README.md +63 -10
  70. package/node_modules/qs/dist/qs.js +17 -17
  71. package/node_modules/qs/eslint.config.mjs +61 -50
  72. package/node_modules/qs/lib/formats.js +7 -2
  73. package/node_modules/qs/lib/parse.js +29 -10
  74. package/node_modules/qs/lib/stringify.js +5 -3
  75. package/node_modules/qs/lib/utils.js +28 -9
  76. package/node_modules/qs/package.json +6 -6
  77. package/node_modules/qs/test/parse.js +335 -2
  78. package/node_modules/qs/test/stringify.js +222 -0
  79. package/node_modules/qs/test/utils.js +61 -3
  80. package/node_modules/semver/classes/range.js +2 -2
  81. package/node_modules/semver/internal/constants.js +30 -0
  82. package/node_modules/semver/internal/trim-comparator-whitespace.js +438 -0
  83. package/node_modules/semver/package.json +1 -1
  84. package/node_modules/ws/README.md +21 -29
  85. package/node_modules/ws/lib/buffer-util.js +13 -2
  86. package/node_modules/ws/lib/sender.js +4 -1
  87. package/node_modules/ws/lib/websocket.js +8 -3
  88. package/node_modules/ws/package.json +1 -1
  89. package/package.json +1 -1
  90. package/node_modules/on-finished/HISTORY.md +0 -98
@@ -5,6 +5,7 @@ var qs = require('../');
5
5
  var utils = require('../lib/utils');
6
6
  var iconv = require('iconv-lite');
7
7
  var SaferBuffer = require('safer-buffer').Buffer;
8
+ var url = require('url');
8
9
  var hasSymbols = require('has-symbols');
9
10
  var mockProperty = require('mock-property');
10
11
  var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
@@ -24,6 +25,28 @@ test('stringify()', function (t) {
24
25
  st.end();
25
26
  });
26
27
 
28
+ t.test('stringifies lone surrogates as U+FFFD', function (st) {
29
+ st.equal(qs.stringify({ a: '\uD800x' }), 'a=%EF%BF%BDx', 'lone high surrogate does not swallow the next character');
30
+ st.equal(qs.stringify({ a: '\uDC00x' }), 'a=%EF%BF%BDx', 'lone low surrogate does not swallow the next character');
31
+ st.equal(qs.stringify({ '\uD800': 'b' }), '%EF%BF%BD=b', 'lone surrogate in a key');
32
+ st.deepEqual(qs.parse(qs.stringify({ a: 'x\uD800y' })), { a: 'x\uFFFDy' }, 'parses back with U+FFFD in place of the lone surrogate');
33
+ st.equal(qs.stringify({ '\uDC00': 'b' }), '%EF%BF%BD=b', 'lone low surrogate in a key');
34
+ st.equal(qs.stringify({ a: { 'b\uD800': 'c' } }), 'a%5Bb%EF%BF%BD%5D=c', 'lone surrogate in a nested key does not swallow the closing bracket');
35
+ st.equal(qs.stringify({ a: '\uD800 x' }, { format: 'RFC1738' }), 'a=%EF%BF%BD+x', 'lone surrogate does not swallow a space in RFC1738');
36
+ st.equal(
37
+ qs.stringify({ 'a\uD800': { b: 'c' } }, { allowDots: true, encodeDotInKeys: true }),
38
+ 'a%EF%BF%BD.b=c',
39
+ 'lone surrogate does not swallow a dot separator'
40
+ );
41
+ st.equal(qs.stringify({ a: ['x\uD800', 'y'] }, { arrayFormat: 'comma' }), 'a=x%EF%BF%BD%2Cy', 'lone surrogate does not swallow a comma');
42
+ st.equal(
43
+ qs.stringify({ a: ['x\uD800', 'y'] }, { arrayFormat: 'comma', encodeValuesOnly: true }),
44
+ 'a=x%EF%BF%BD,y',
45
+ 'lone surrogate at the end of a comma-joined element encodes as U+FFFD'
46
+ );
47
+ st.end();
48
+ });
49
+
27
50
  t.test('stringifies falsy values', function (st) {
28
51
  st.equal(qs.stringify(undefined), '');
29
52
  st.equal(qs.stringify(null), '');
@@ -520,6 +543,24 @@ test('stringify()', function (t) {
520
543
  st.end();
521
544
  });
522
545
 
546
+ t.test('allowEmptyArrays keys that need no encoding', function (st) {
547
+ st.equal(qs.stringify({ foo: [] }, { allowEmptyArrays: true, format: 'RFC1738' }), 'foo[]', 'a top-level key in RFC1738');
548
+ st.equal(
549
+ qs.stringify({ a: { b: [] }, c: 'd e' }, { allowEmptyArrays: true, encodeValuesOnly: true }),
550
+ 'a[b][]&c=d%20e',
551
+ 'a nested key with encodeValuesOnly'
552
+ );
553
+ st.equal(qs.stringify({ a: { b: [] } }, { allowEmptyArrays: true, encode: false }), 'a[b][]', 'a nested key with encode: false');
554
+ st.equal(qs.stringify({ a: { b: [] } }, { allowEmptyArrays: true, allowDots: true }), 'a.b[]', 'a nested key with allowDots');
555
+ st.equal(
556
+ qs.stringify({ a: { b: [] } }, { allowEmptyArrays: true, allowDots: true, format: 'RFC1738' }),
557
+ 'a.b[]',
558
+ 'a nested key with allowDots in RFC1738'
559
+ );
560
+
561
+ st.end();
562
+ });
563
+
523
564
  t.test('allowEmptyArrays + strictNullHandling', function (st) {
524
565
  st.equal(
525
566
  qs.stringify(
@@ -565,6 +606,62 @@ test('stringify()', function (t) {
565
606
  st.end();
566
607
  });
567
608
 
609
+ t.test('should encode the key of an empty array when allowEmptyArrays is set', function (st) {
610
+ st.equal(
611
+ qs.stringify({ 'a b': [] }, { allowEmptyArrays: true }),
612
+ 'a%20b[]',
613
+ 'default (RFC3986) percent-encodes the space in the key'
614
+ );
615
+ st.equal(
616
+ qs.stringify({ 'a b': [] }, { allowEmptyArrays: true, format: 'RFC1738' }),
617
+ 'a+b[]',
618
+ 'RFC1738 encodes the space in the key as a plus'
619
+ );
620
+ st.equal(
621
+ qs.stringify({ 'a b': [] }, { allowEmptyArrays: true, encodeValuesOnly: true }),
622
+ 'a b[]',
623
+ 'encodeValuesOnly leaves the key unencoded'
624
+ );
625
+ st.equal(
626
+ qs.stringify({ 'a b': [] }, { allowEmptyArrays: true, encode: false }),
627
+ 'a b[]',
628
+ 'encode: false leaves the key unencoded'
629
+ );
630
+
631
+ st.deepEqual(
632
+ qs.parse(qs.stringify({ 'a b': [], 'a&b=c': [] }, { allowEmptyArrays: true }), { allowEmptyArrays: true }),
633
+ { 'a b': [], 'a&b=c': [] },
634
+ 'the encoded keys round-trip back to the original, including `&` and `=`'
635
+ );
636
+ st.equal(
637
+ qs.stringify({ 'a b': ['x'] }, { allowEmptyArrays: true, arrayFormat: 'brackets' }),
638
+ 'a%20b%5B%5D=x',
639
+ 'the same key with a value encodes the key prefix identically'
640
+ );
641
+ st.equal(
642
+ qs.stringify({ a: { 'b c': [] } }, { allowEmptyArrays: true }),
643
+ 'a%5Bb%20c%5D[]',
644
+ 'a nested key prefix is encoded like the value path encodes it'
645
+ );
646
+ st.equal(
647
+ qs.stringify({ a: { b: [] } }, { allowEmptyArrays: true }),
648
+ 'a%5Bb%5D[]',
649
+ 'a nested key that needs no encoding still has its brackets encoded'
650
+ );
651
+ st.equal(
652
+ qs.stringify({ 'a.b': [] }, { allowEmptyArrays: true, allowDots: true, encodeDotInKeys: true }),
653
+ 'a%252Eb[]',
654
+ 'encodeDotInKeys double-encodes the dot, as on the value path'
655
+ );
656
+ st.deepEqual(
657
+ qs.parse('a%252Eb[]', { allowEmptyArrays: true, allowDots: true, decodeDotInKeys: true }),
658
+ { 'a.b': [] },
659
+ 'the encodeDotInKeys output round-trips'
660
+ );
661
+
662
+ st.end();
663
+ });
664
+
568
665
  t.test('stringifies an array value with one item vs multiple items', function (st) {
569
666
  st.test('non-array item', function (s2t) {
570
667
  s2t.equal(qs.stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a=c');
@@ -1314,6 +1411,53 @@ test('stringify()', function (t) {
1314
1411
  st.end();
1315
1412
  });
1316
1413
 
1414
+ t.test('applies sort to nested keys selected by filter=array', function (st) {
1415
+ var asc = function (a, b) { return a.localeCompare(b); };
1416
+ var desc = function (a, b) { return b.localeCompare(a); };
1417
+
1418
+ st.equal(
1419
+ qs.stringify({ a: { c: 1, b: 2 }, z: 3 }, { filter: ['z', 'a', 'c', 'b'], sort: asc, encode: false }),
1420
+ 'a[b]=2&a[c]=1&z=3',
1421
+ 'nested keys are sorted, not left in filter order'
1422
+ );
1423
+ st.equal(
1424
+ qs.stringify({ a: { c: 1, b: 2 }, z: 3 }, { filter: ['z', 'b', 'a', 'c'], sort: desc, encode: false }),
1425
+ 'z=3&a[c]=1&a[b]=2',
1426
+ 'nested keys follow a descending sort'
1427
+ );
1428
+ st.equal(
1429
+ qs.stringify({ a: [{ y: 1, x: 2 }] }, { filter: ['a', '0', 'y', 'x'], sort: asc, encode: false }),
1430
+ 'a[0][x]=2&a[0][y]=1',
1431
+ 'keys of objects nested in arrays are sorted'
1432
+ );
1433
+ st.equal(
1434
+ qs.stringify({ a: { c: 1, b: 2 }, z: 3 }, { filter: ['z', 'a', 'c', 'b'], encode: false }),
1435
+ 'z=3&a[c]=1&a[b]=2',
1436
+ 'without sort, keys keep filter order at every level'
1437
+ );
1438
+
1439
+ st.end();
1440
+ });
1441
+
1442
+ t.test('does not reorder the caller\'s filter array when sorting', function (st) {
1443
+ var filter = ['z', 'a', 'c', 'b'];
1444
+ var asc = function (a, b) { return a.localeCompare(b); };
1445
+
1446
+ st.equal(
1447
+ qs.stringify({ a: { c: 1, b: 2 }, z: 3 }, { filter: filter, sort: asc, encode: false }),
1448
+ 'a[b]=2&a[c]=1&z=3',
1449
+ 'keys are sorted at every level'
1450
+ );
1451
+ st.deepEqual(filter, ['z', 'a', 'c', 'b'], 'filter array is not mutated');
1452
+ st.equal(
1453
+ qs.stringify({ a: { c: 1, b: 2 }, z: 3 }, { filter: filter, encode: false }),
1454
+ 'z=3&a[c]=1&a[b]=2',
1455
+ 'reusing the filter without sort keeps its own order'
1456
+ );
1457
+
1458
+ st.end();
1459
+ });
1460
+
1317
1461
  t.test('supports custom representations when filter=function', function (st) {
1318
1462
  var calls = 0;
1319
1463
  var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } };
@@ -1564,6 +1708,7 @@ test('stringify()', function (t) {
1564
1708
  st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC1738 }), 'a+b=a+b');
1565
1709
 
1566
1710
  st.equal(qs.stringify({ 'foo(ref)': 'bar' }, { format: qs.formats.RFC1738 }), 'foo(ref)=bar');
1711
+ st.equal(qs.stringify({ 'a~*': '~*()' }, { format: qs.formats.RFC1738 }), 'a~%2A=~%2A()', 'leaves `~` unencoded and encodes `*`');
1567
1712
 
1568
1713
  st.end();
1569
1714
  });
@@ -1572,6 +1717,83 @@ test('stringify()', function (t) {
1572
1717
  st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c');
1573
1718
  st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d');
1574
1719
  st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC3986 }), 'a%20b=a%20b');
1720
+ st.equal(qs.stringify({ 'a~*': '~*()' }, { format: qs.formats.RFC3986 }), 'a~%2A=~%2A%28%29', 'leaves `~` unencoded, and encodes `*` and parens');
1721
+
1722
+ st.end();
1723
+ });
1724
+
1725
+ t.test('WHATWG serialization', function (st) {
1726
+ st.equal(qs.formats.WHATWG, 'WHATWG', 'is exported');
1727
+ st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.WHATWG }), 'a=b+c');
1728
+ st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.WHATWG }), 'a+b=c+d');
1729
+ st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.WHATWG }), 'a+b=a+b');
1730
+
1731
+ st.equal(qs.stringify({ a: '~' }, { format: qs.formats.WHATWG }), 'a=%7E', 'encodes `~`');
1732
+ st.equal(qs.stringify({ a: '*' }, { format: qs.formats.WHATWG }), 'a=*', 'does not encode `*`');
1733
+ st.equal(qs.stringify({ 'foo(ref)': 'bar' }, { format: qs.formats.WHATWG }), 'foo%28ref%29=bar', 'encodes parentheses');
1734
+ st.equal(qs.stringify({ a: '-._' }, { format: qs.formats.WHATWG }), 'a=-._');
1735
+ st.equal(qs.stringify({ a: '+&=' }, { format: qs.formats.WHATWG }), 'a=%2B%26%3D');
1736
+ st.equal(qs.stringify({ a: { b: 'c d' } }, { format: qs.formats.WHATWG }), 'a%5Bb%5D=c+d');
1737
+ st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.WHATWG, encode: false }), 'a=b c', 'encode: false leaves the value alone');
1738
+
1739
+ st.equal(
1740
+ qs.stringify({ 'a~b*': { 'c d': '~* ' } }, { format: qs.formats.WHATWG, encodeValuesOnly: true }),
1741
+ 'a~b*[c d]=%7E*+',
1742
+ 'encodeValuesOnly: leaves keys alone'
1743
+ );
1744
+ st.equal(
1745
+ qs.stringify({ a: '~*\u00e9 ' }, { format: qs.formats.WHATWG, charset: 'iso-8859-1' }),
1746
+ 'a=%7E*%E9+',
1747
+ 'charset iso-8859-1'
1748
+ );
1749
+ st.equal(
1750
+ qs.stringify({ a: '~* ' }, {
1751
+ format: qs.formats.WHATWG,
1752
+ encoder: function (str, defaultEncoder, charset, type, format) {
1753
+ return defaultEncoder(str, defaultEncoder, charset, type, format);
1754
+ }
1755
+ }),
1756
+ 'a=%7E*+',
1757
+ 'an encoder wrapping the default encoder'
1758
+ );
1759
+ st.equal(
1760
+ qs.stringify({ a: ['~ x', '*'] }, { format: qs.formats.WHATWG, arrayFormat: 'comma' }),
1761
+ 'a=%7E+x%2C*',
1762
+ 'arrayFormat comma'
1763
+ );
1764
+
1765
+ st.end();
1766
+ });
1767
+
1768
+ var USP = typeof URLSearchParams === 'function' ? URLSearchParams : url.URLSearchParams;
1769
+
1770
+ t.test('WHATWG serialization matches URLSearchParams', { skip: typeof USP !== 'function' }, function (st) {
1771
+ var chars = [];
1772
+ for (var c = 0; c < 0x80; c++) {
1773
+ chars[chars.length] = String.fromCharCode(c);
1774
+ }
1775
+ chars.push('\u00e9', '\u20ac', '\uFFFF', '\uD83D\uDCA9', 'a b~c*d(e)f', '\uD800', '\uDC00', 'x\uDC00y');
1776
+
1777
+ for (var i = 0; i < chars.length; i++) {
1778
+ var key = {};
1779
+ key[chars[i]] = 'v';
1780
+ st.equal(
1781
+ qs.stringify({ k: chars[i] }, { format: qs.formats.WHATWG }),
1782
+ new USP([['k', chars[i]]]).toString(),
1783
+ 'value ' + JSON.stringify(chars[i])
1784
+ );
1785
+ st.equal(
1786
+ qs.stringify(key, { format: qs.formats.WHATWG }),
1787
+ new USP([[chars[i], 'v']]).toString(),
1788
+ 'key ' + JSON.stringify(chars[i])
1789
+ );
1790
+ }
1791
+
1792
+ st.equal(
1793
+ qs.stringify({ a: { 'b~': 'c d' } }, { format: qs.formats.WHATWG }),
1794
+ new USP([['a[b~]', 'c d']]).toString(),
1795
+ 'nested key'
1796
+ );
1575
1797
 
1576
1798
  st.end();
1577
1799
  });
@@ -742,7 +742,7 @@ test('encode', function (t) {
742
742
  loneExpected += 'a';
743
743
  }
744
744
  loneBoundary += '\uD83DX';
745
- loneExpected += '%F0%9F%91%98';
745
+ loneExpected += '%EF%BF%BDX';
746
746
 
747
747
  t.equal(
748
748
  utils.encode(loneBoundary),
@@ -750,6 +750,17 @@ test('encode', function (t) {
750
750
  'a lone high surrogate at a chunk boundary encodes the same as mid-chunk'
751
751
  );
752
752
 
753
+ t.equal(
754
+ utils.encode(loneBoundary.slice(0, 1023) + '\uDC00X'),
755
+ loneExpected.slice(0, 1023) + '%EF%BF%BDX',
756
+ 'a lone low surrogate at a chunk boundary does not consume the next character'
757
+ );
758
+ t.equal(
759
+ utils.encode(loneBoundary.slice(0, 1024)),
760
+ loneExpected.slice(0, 1023) + '%EF%BF%BD',
761
+ 'a lone high surrogate ending a string of exactly one chunk encodes as U+FFFD'
762
+ );
763
+
753
764
  t.equal(
754
765
  utils.encode('\x28\x29'),
755
766
  '%28%29',
@@ -761,8 +772,30 @@ test('encode', function (t) {
761
772
  'does not encode parens in RFC1738'
762
773
  );
763
774
 
775
+ t.equal(
776
+ utils.encode('~*()'),
777
+ '~%2A%28%29',
778
+ 'leaves `~` unencoded, and encodes `*` and parens, by default'
779
+ );
780
+ t.equal(
781
+ utils.encode('~*()', null, null, null, 'RFC3986'),
782
+ '~%2A%28%29',
783
+ 'leaves `~` unencoded, and encodes `*` and parens, in RFC3986'
784
+ );
785
+ t.equal(
786
+ utils.encode('~*() ', null, null, null, 'RFC1738'),
787
+ '~%2A()%20',
788
+ 'leaves `~` and parens unencoded, and encodes `*` and spaces, in RFC1738'
789
+ );
790
+
764
791
  // todo RFC1738 format
765
792
 
793
+ t.equal(
794
+ utils.encode('~*()', null, null, null, 'WHATWG'),
795
+ '%7E*%28%29',
796
+ 'encodes `~` and parens, but not `*`, in WHATWG'
797
+ );
798
+
766
799
  t.equal(
767
800
  utils.encode('Āက豈'),
768
801
  '%C4%80%E1%80%80%EF%A4%80',
@@ -771,8 +804,33 @@ test('encode', function (t) {
771
804
 
772
805
  t.equal(
773
806
  utils.encode('\uD83D \uDCA9'),
774
- '%F0%9F%90%A0%F0%BA%90%80',
775
- 'encodes lone surrogates'
807
+ '%EF%BF%BD%20%EF%BF%BD',
808
+ 'encodes lone surrogates as U+FFFD, without consuming the next character'
809
+ );
810
+ t.equal(
811
+ utils.encode('\uDCA9\uD83D'),
812
+ '%EF%BF%BD%EF%BF%BD',
813
+ 'encodes a reversed surrogate pair as two U+FFFD'
814
+ );
815
+ t.equal(
816
+ utils.encode('x\uD83D'),
817
+ 'x%EF%BF%BD',
818
+ 'encodes a trailing lone high surrogate as U+FFFD'
819
+ );
820
+ t.equal(
821
+ utils.encode('\uD83D\uD83D\uDCA9'),
822
+ '%EF%BF%BD%F0%9F%92%A9',
823
+ 'a lone high surrogate does not prevent the following pair from encoding'
824
+ );
825
+ t.equal(
826
+ utils.encode('\uD83D\uE000'),
827
+ '%EF%BF%BD%EE%80%80',
828
+ 'a high surrogate followed by a code unit above the low surrogate range is not combined'
829
+ );
830
+ t.equal(
831
+ utils.encode('\uDC00\uDC00'),
832
+ '%EF%BF%BD%EF%BF%BD',
833
+ 'a low surrogate followed by a low surrogate is not combined'
776
834
  );
777
835
 
778
836
  t.end();
@@ -119,7 +119,7 @@ class Range {
119
119
  debug('hyphen replace', range)
120
120
 
121
121
  // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
122
- range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
122
+ range = trimComparatorWhitespace(range)
123
123
  debug('comparator trim', range)
124
124
 
125
125
  // `~ 1.2.3` => `~1.2.3`
@@ -224,11 +224,11 @@ const parseOptions = require('../internal/parse-options')
224
224
  const Comparator = require('./comparator')
225
225
  const debug = require('../internal/debug')
226
226
  const SemVer = require('./semver')
227
+ const trimComparatorWhitespace = require('../internal/trim-comparator-whitespace')
227
228
  const {
228
229
  safeRe: re,
229
230
  src,
230
231
  t,
231
- comparatorTrimReplace,
232
232
  tildeTrimReplace,
233
233
  caretTrimReplace,
234
234
  } = require('../internal/re')
@@ -15,6 +15,35 @@ const MAX_SAFE_COMPONENT_LENGTH = 16
15
15
  // the shortest version with a build 0.0.0+BUILD.
16
16
  const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6
17
17
 
18
+ // ECMAScript whitespace and line terminators matched by \s.
19
+ const WHITESPACE_CHARACTERS = [
20
+ '\t',
21
+ '\n',
22
+ '\v',
23
+ '\f',
24
+ '\r',
25
+ ' ',
26
+ '\u00a0',
27
+ '\u1680',
28
+ '\u2000',
29
+ '\u2001',
30
+ '\u2002',
31
+ '\u2003',
32
+ '\u2004',
33
+ '\u2005',
34
+ '\u2006',
35
+ '\u2007',
36
+ '\u2008',
37
+ '\u2009',
38
+ '\u200a',
39
+ '\u2028',
40
+ '\u2029',
41
+ '\u202f',
42
+ '\u205f',
43
+ '\u3000',
44
+ '\ufeff',
45
+ ]
46
+
18
47
  const RELEASE_TYPES = [
19
48
  'major',
20
49
  'premajor',
@@ -30,6 +59,7 @@ module.exports = {
30
59
  MAX_SAFE_COMPONENT_LENGTH,
31
60
  MAX_SAFE_BUILD_LENGTH,
32
61
  MAX_SAFE_INTEGER,
62
+ WHITESPACE_CHARACTERS,
33
63
  RELEASE_TYPES,
34
64
  SEMVER_SPEC_VERSION,
35
65
  FLAG_INCLUDE_PRERELEASE: 0b001,