utils.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. const PrimitiveType = 1;
  2. const ObjectType = 2;
  3. const ArrayType = 3;
  4. const PromiseType = 4;
  5. const ReadableStringType = 5;
  6. const ReadableObjectType = 6;
  7. // https://tc39.es/ecma262/#table-json-single-character-escapes
  8. const escapableCharCodeSubstitution = { // JSON Single Character Escape Sequences
  9. 0x08: '\\b',
  10. 0x09: '\\t',
  11. 0x0a: '\\n',
  12. 0x0c: '\\f',
  13. 0x0d: '\\r',
  14. 0x22: '\\\"',
  15. 0x5c: '\\\\'
  16. };
  17. function isLeadingSurrogate(code) {
  18. return code >= 0xD800 && code <= 0xDBFF;
  19. }
  20. function isTrailingSurrogate(code) {
  21. return code >= 0xDC00 && code <= 0xDFFF;
  22. }
  23. function isReadableStream(value) {
  24. return (
  25. typeof value.pipe === 'function' &&
  26. typeof value._read === 'function' &&
  27. typeof value._readableState === 'object' && value._readableState !== null
  28. );
  29. }
  30. function replaceValue(holder, key, value, replacer) {
  31. if (value && typeof value.toJSON === 'function') {
  32. value = value.toJSON();
  33. }
  34. if (replacer !== null) {
  35. value = replacer.call(holder, String(key), value);
  36. }
  37. switch (typeof value) {
  38. case 'function':
  39. case 'symbol':
  40. value = undefined;
  41. break;
  42. case 'object':
  43. if (value !== null) {
  44. const cls = value.constructor;
  45. if (cls === String || cls === Number || cls === Boolean) {
  46. value = value.valueOf();
  47. }
  48. }
  49. break;
  50. }
  51. return value;
  52. }
  53. function getTypeNative(value) {
  54. if (value === null || typeof value !== 'object') {
  55. return PrimitiveType;
  56. }
  57. if (Array.isArray(value)) {
  58. return ArrayType;
  59. }
  60. return ObjectType;
  61. }
  62. function getTypeAsync(value) {
  63. if (value === null || typeof value !== 'object') {
  64. return PrimitiveType;
  65. }
  66. if (typeof value.then === 'function') {
  67. return PromiseType;
  68. }
  69. if (isReadableStream(value)) {
  70. return value._readableState.objectMode ? ReadableObjectType : ReadableStringType;
  71. }
  72. if (Array.isArray(value)) {
  73. return ArrayType;
  74. }
  75. return ObjectType;
  76. }
  77. function normalizeReplacer(replacer) {
  78. if (typeof replacer === 'function') {
  79. return replacer;
  80. }
  81. if (Array.isArray(replacer)) {
  82. const allowlist = new Set(replacer
  83. .map(item => {
  84. const cls = item && item.constructor;
  85. return cls === String || cls === Number ? String(item) : null;
  86. })
  87. .filter(item => typeof item === 'string')
  88. );
  89. return [...allowlist];
  90. }
  91. return null;
  92. }
  93. function normalizeSpace(space) {
  94. if (typeof space === 'number') {
  95. if (!Number.isFinite(space) || space < 1) {
  96. return false;
  97. }
  98. return ' '.repeat(Math.min(space, 10));
  99. }
  100. if (typeof space === 'string') {
  101. return space.slice(0, 10) || false;
  102. }
  103. return false;
  104. }
  105. module.exports = {
  106. escapableCharCodeSubstitution,
  107. isLeadingSurrogate,
  108. isTrailingSurrogate,
  109. type: {
  110. PRIMITIVE: PrimitiveType,
  111. PROMISE: PromiseType,
  112. ARRAY: ArrayType,
  113. OBJECT: ObjectType,
  114. STRING_STREAM: ReadableStringType,
  115. OBJECT_STREAM: ReadableObjectType
  116. },
  117. isReadableStream,
  118. replaceValue,
  119. getTypeNative,
  120. getTypeAsync,
  121. normalizeReplacer,
  122. normalizeSpace
  123. };