PlainObjectSerializer.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. */
  4. "use strict";
  5. /** @typedef {import("./ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
  6. /** @typedef {import("./ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
  7. const cache = new WeakMap();
  8. class ObjectStructure {
  9. constructor() {
  10. this.keys = undefined;
  11. this.children = undefined;
  12. }
  13. getKeys(keys) {
  14. if (this.keys === undefined) this.keys = keys;
  15. return this.keys;
  16. }
  17. key(key) {
  18. if (this.children === undefined) this.children = new Map();
  19. const child = this.children.get(key);
  20. if (child !== undefined) return child;
  21. const newChild = new ObjectStructure();
  22. this.children.set(key, newChild);
  23. return newChild;
  24. }
  25. }
  26. const getCachedKeys = (keys, cacheAssoc) => {
  27. let root = cache.get(cacheAssoc);
  28. if (root === undefined) {
  29. root = new ObjectStructure();
  30. cache.set(cacheAssoc, root);
  31. }
  32. let current = root;
  33. for (const key of keys) {
  34. current = current.key(key);
  35. }
  36. return current.getKeys(keys);
  37. };
  38. class PlainObjectSerializer {
  39. /**
  40. * @param {object} obj plain object
  41. * @param {ObjectSerializerContext} context context
  42. */
  43. serialize(obj, context) {
  44. const keys = Object.keys(obj);
  45. if (keys.length > 128) {
  46. // Objects with so many keys are unlikely to share structure
  47. // with other objects
  48. context.write(keys);
  49. for (const key of keys) {
  50. context.write(obj[key]);
  51. }
  52. } else if (keys.length > 1) {
  53. context.write(getCachedKeys(keys, context.write));
  54. for (const key of keys) {
  55. context.write(obj[key]);
  56. }
  57. } else if (keys.length === 1) {
  58. const key = keys[0];
  59. context.write(key);
  60. context.write(obj[key]);
  61. } else {
  62. context.write(null);
  63. }
  64. }
  65. /**
  66. * @param {ObjectDeserializerContext} context context
  67. * @returns {object} plain object
  68. */
  69. deserialize(context) {
  70. const keys = context.read();
  71. const obj = {};
  72. if (Array.isArray(keys)) {
  73. for (const key of keys) {
  74. obj[key] = context.read();
  75. }
  76. } else if (keys !== null) {
  77. obj[keys] = context.read();
  78. }
  79. return obj;
  80. }
  81. }
  82. module.exports = PlainObjectSerializer;