index.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /**
  2. * Copyright (c) 2018-present, Facebook, Inc. All rights reserved.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. *
  8. */
  9. 'use strict';
  10. Object.defineProperty(exports, "__esModule", {
  11. value: true
  12. });
  13. exports.deserialize = deserialize;
  14. exports.serialize = serialize;
  15. exports.readFileSync = readFileSync;
  16. exports.writeFileSync = writeFileSync;
  17. var _fs;
  18. function _load_fs() {
  19. return _fs = _interopRequireDefault(require('fs'));
  20. }
  21. var _v;
  22. function _load_v() {
  23. return _v = _interopRequireDefault(require('v8'));
  24. }
  25. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  26. // JSON and V8 serializers are both stable when it comes to compatibility. The
  27. // current JSON specification is well defined in RFC 8259, and V8 ensures that
  28. // the versions are compatible by encoding the serialization version in the own
  29. // generated buffer.
  30. const JS_TYPE = '__$t__';
  31. const JS_VALUE = '__$v__';
  32. const JS_VF = '__$f__';
  33. function replacer(key, value) {
  34. // NaN cannot be in a switch statement, because NaN !== NaN.
  35. if (Number.isNaN(value)) {
  36. return { [JS_TYPE]: 'n' };
  37. }
  38. switch (value) {
  39. case undefined:
  40. return { [JS_TYPE]: 'u' };
  41. case +Infinity:
  42. return { [JS_TYPE]: '+' };
  43. case -Infinity:
  44. return { [JS_TYPE]: '-' };
  45. }
  46. switch (value && value.constructor) {
  47. case Date:
  48. return { [JS_TYPE]: 'd', [JS_VALUE]: value.getTime() };
  49. case RegExp:
  50. return { [JS_TYPE]: 'r', [JS_VALUE]: value.source, [JS_VF]: value.flags };
  51. case Set:
  52. return { [JS_TYPE]: 's', [JS_VALUE]: Array.from(value) };
  53. case Map:
  54. return { [JS_TYPE]: 'm', [JS_VALUE]: Array.from(value) };
  55. case Buffer:
  56. return { [JS_TYPE]: 'b', [JS_VALUE]: value.toString('latin1') };
  57. }
  58. return value;
  59. }
  60. function reviver(key, value) {
  61. if (!value || typeof value !== 'object' && !value.hasOwnProperty(JS_TYPE)) {
  62. return value;
  63. }
  64. switch (value[JS_TYPE]) {
  65. case 'u':
  66. return undefined;
  67. case 'n':
  68. return NaN;
  69. case '+':
  70. return +Infinity;
  71. case '-':
  72. return -Infinity;
  73. case 'd':
  74. return new Date(value[JS_VALUE]);
  75. case 'r':
  76. return new RegExp(value[JS_VALUE], value[JS_VF]);
  77. case 's':
  78. return new Set(value[JS_VALUE]);
  79. case 'm':
  80. return new Map(value[JS_VALUE]);
  81. case 'b':
  82. return Buffer.from(value[JS_VALUE], 'latin1');
  83. }
  84. return value;
  85. }
  86. function jsonStringify(content) {
  87. // Not pretty, but the ES JSON spec says that "toJSON" will be called before
  88. // getting into your replacer, so we have to remove them beforehand. See
  89. // https://www.ecma-international.org/ecma-262/#sec-serializejsonproperty
  90. // section 2.b for more information.
  91. const dateToJSON = Date.prototype.toJSON;
  92. const bufferToJSON = Buffer.prototype.toJSON;
  93. /* eslint-disable no-extend-native */
  94. try {
  95. // $FlowFixMe: intentional removal of "toJSON" property.
  96. Date.prototype.toJSON = undefined;
  97. // $FlowFixMe: intentional removal of "toJSON" property.
  98. Buffer.prototype.toJSON = undefined;
  99. return JSON.stringify(content, replacer);
  100. } finally {
  101. // $FlowFixMe: intentional assignment of "toJSON" property.
  102. Date.prototype.toJSON = dateToJSON;
  103. // $FlowFixMe: intentional assignment of "toJSON" property.
  104. Buffer.prototype.toJSON = bufferToJSON;
  105. }
  106. /* eslint-enable no-extend-native */
  107. }
  108. function jsonParse(content) {
  109. return JSON.parse(content, reviver);
  110. }
  111. // In memory functions.
  112. function deserialize(buffer) {
  113. return (_v || _load_v()).default.deserialize ? (_v || _load_v()).default.deserialize(buffer) : jsonParse(buffer.toString('utf8'));
  114. }
  115. function serialize(content) {
  116. return (_v || _load_v()).default.serialize ? (_v || _load_v()).default.serialize(content) : Buffer.from(jsonStringify(content));
  117. }
  118. // Synchronous filesystem functions.
  119. function readFileSync(filePath) {
  120. return (_v || _load_v()).default.deserialize ? (_v || _load_v()).default.deserialize((_fs || _load_fs()).default.readFileSync(filePath)) : jsonParse((_fs || _load_fs()).default.readFileSync(filePath, 'utf8'));
  121. }
  122. function writeFileSync(filePath, content) {
  123. return (_v || _load_v()).default.serialize ? (_fs || _load_fs()).default.writeFileSync(filePath, (_v || _load_v()).default.serialize(content)) : (_fs || _load_fs()).default.writeFileSync(filePath, jsonStringify(content), 'utf8');
  124. }
  125. exports.default = {
  126. deserialize,
  127. readFileSync,
  128. serialize,
  129. writeFileSync
  130. };