index.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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) {
  26. return obj && obj.__esModule ? obj : {default: obj};
  27. }
  28. // JSON and V8 serializers are both stable when it comes to compatibility. The
  29. // current JSON specification is well defined in RFC 8259, and V8 ensures that
  30. // the versions are compatible by encoding the serialization version in the own
  31. // generated buffer.
  32. const JS_TYPE = '__$t__';
  33. const JS_VALUE = '__$v__';
  34. const JS_VF = '__$f__';
  35. function replacer(key, value) {
  36. // NaN cannot be in a switch statement, because NaN !== NaN.
  37. if (Number.isNaN(value)) {
  38. return {[JS_TYPE]: 'n'};
  39. }
  40. switch (value) {
  41. case undefined:
  42. return {[JS_TYPE]: 'u'};
  43. case +Infinity:
  44. return {[JS_TYPE]: '+'};
  45. case -Infinity:
  46. return {[JS_TYPE]: '-'};
  47. }
  48. switch (value && value.constructor) {
  49. case Date:
  50. return {[JS_TYPE]: 'd', [JS_VALUE]: value.getTime()};
  51. case RegExp:
  52. return {[JS_TYPE]: 'r', [JS_VALUE]: value.source, [JS_VF]: value.flags};
  53. case Set:
  54. return {[JS_TYPE]: 's', [JS_VALUE]: Array.from(value)};
  55. case Map:
  56. return {[JS_TYPE]: 'm', [JS_VALUE]: Array.from(value)};
  57. case Buffer:
  58. return {[JS_TYPE]: 'b', [JS_VALUE]: value.toString('latin1')};
  59. }
  60. return value;
  61. }
  62. function reviver(key, value) {
  63. if (!value || (typeof value !== 'object' && !value.hasOwnProperty(JS_TYPE))) {
  64. return value;
  65. }
  66. switch (value[JS_TYPE]) {
  67. case 'u':
  68. return undefined;
  69. case 'n':
  70. return NaN;
  71. case '+':
  72. return +Infinity;
  73. case '-':
  74. return -Infinity;
  75. case 'd':
  76. return new Date(value[JS_VALUE]);
  77. case 'r':
  78. return new RegExp(value[JS_VALUE], value[JS_VF]);
  79. case 's':
  80. return new Set(value[JS_VALUE]);
  81. case 'm':
  82. return new Map(value[JS_VALUE]);
  83. case 'b':
  84. return Buffer.from(value[JS_VALUE], 'latin1');
  85. }
  86. return value;
  87. }
  88. function jsonStringify(content) {
  89. // Not pretty, but the ES JSON spec says that "toJSON" will be called before
  90. // getting into your replacer, so we have to remove them beforehand. See
  91. // https://www.ecma-international.org/ecma-262/#sec-serializejsonproperty
  92. // section 2.b for more information.
  93. const dateToJSON = Date.prototype.toJSON;
  94. const bufferToJSON = Buffer.prototype.toJSON;
  95. /* eslint-disable no-extend-native */
  96. try {
  97. // $FlowFixMe: intentional removal of "toJSON" property.
  98. Date.prototype.toJSON = undefined;
  99. // $FlowFixMe: intentional removal of "toJSON" property.
  100. Buffer.prototype.toJSON = undefined;
  101. return JSON.stringify(content, replacer);
  102. } finally {
  103. // $FlowFixMe: intentional assignment of "toJSON" property.
  104. Date.prototype.toJSON = dateToJSON;
  105. // $FlowFixMe: intentional assignment of "toJSON" property.
  106. Buffer.prototype.toJSON = bufferToJSON;
  107. }
  108. /* eslint-enable no-extend-native */
  109. }
  110. function jsonParse(content) {
  111. return JSON.parse(content, reviver);
  112. }
  113. // In memory functions.
  114. function deserialize(buffer) {
  115. // $FlowFixMe - Node 8+ only
  116. return (_v || _load_v()).default.deserialize
  117. ? (_v || _load_v()).default.deserialize(buffer)
  118. : jsonParse(buffer.toString('utf8'));
  119. }
  120. function serialize(content) {
  121. // $FlowFixMe - Node 8+ only
  122. return (_v || _load_v()).default.serialize
  123. ? (_v || _load_v()).default.serialize(content)
  124. : Buffer.from(jsonStringify(content));
  125. }
  126. // Synchronous filesystem functions.
  127. function readFileSync(filePath) {
  128. // $FlowFixMe - Node 8+ only
  129. return (_v || _load_v()).default.deserialize
  130. ? (_v || _load_v()).default.deserialize(
  131. (_fs || _load_fs()).default.readFileSync(filePath)
  132. )
  133. : jsonParse((_fs || _load_fs()).default.readFileSync(filePath, 'utf8'));
  134. }
  135. function writeFileSync(filePath, content) {
  136. // $FlowFixMe - Node 8+ only
  137. return (_v || _load_v()).default.serialize
  138. ? (_fs || _load_fs()).default.writeFileSync(
  139. filePath,
  140. (_v || _load_v()).default.serialize(content)
  141. )
  142. : (_fs || _load_fs()).default.writeFileSync(
  143. filePath,
  144. jsonStringify(content),
  145. 'utf8'
  146. );
  147. }
  148. exports.default = {
  149. deserialize,
  150. readFileSync,
  151. serialize,
  152. writeFileSync
  153. };