index.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. var Flatted = (function (Primitive, primitive) {
  2. /*!
  3. * ISC License
  4. *
  5. * Copyright (c) 2018, Andrea Giammarchi, @WebReflection
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for any
  8. * purpose with or without fee is hereby granted, provided that the above
  9. * copyright notice and this permission notice appear in all copies.
  10. *
  11. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  12. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  13. * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  14. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  15. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  16. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  17. * PERFORMANCE OF THIS SOFTWARE.
  18. */
  19. var Flatted = {
  20. parse: function parse(text, reviver) {
  21. var input = JSON.parse(text, Primitives).map(primitives);
  22. var value = input[0];
  23. var $ = reviver || noop;
  24. var tmp = typeof value === 'object' && value ?
  25. revive(input, new Set, value, $) :
  26. value;
  27. return $.call({'': tmp}, '', tmp);
  28. },
  29. stringify: function stringify(value, replacer, space) {
  30. for (var
  31. firstRun,
  32. known = new Map,
  33. input = [],
  34. output = [],
  35. $ = replacer && typeof replacer === typeof input ?
  36. function (k, v) {
  37. if (k === '' || -1 < replacer.indexOf(k)) return v;
  38. } :
  39. (replacer || noop),
  40. i = +set(known, input, $.call({'': value}, '', value)),
  41. replace = function (key, value) {
  42. if (firstRun) {
  43. firstRun = !firstRun;
  44. return value;
  45. }
  46. var after = $.call(this, key, value);
  47. switch (typeof after) {
  48. case 'object':
  49. if (after === null) return after;
  50. case primitive:
  51. return known.get(after) || set(known, input, after);
  52. }
  53. return after;
  54. };
  55. i < input.length; i++
  56. ) {
  57. firstRun = true;
  58. output[i] = JSON.stringify(input[i], replace, space);
  59. }
  60. return '[' + output.join(',') + ']';
  61. }
  62. };
  63. return Flatted;
  64. function noop(key, value) {
  65. return value;
  66. }
  67. function revive(input, parsed, output, $) {
  68. return Object.keys(output).reduce(
  69. function (output, key) {
  70. var value = output[key];
  71. if (value instanceof Primitive) {
  72. var tmp = input[value];
  73. if (typeof tmp === 'object' && !parsed.has(tmp)) {
  74. parsed.add(tmp);
  75. output[key] = $.call(output, key, revive(input, parsed, tmp, $));
  76. } else {
  77. output[key] = $.call(output, key, tmp);
  78. }
  79. } else
  80. output[key] = $.call(output, key, value);
  81. return output;
  82. },
  83. output
  84. );
  85. }
  86. function set(known, input, value) {
  87. var index = Primitive(input.push(value) - 1);
  88. known.set(value, index);
  89. return index;
  90. }
  91. // the two kinds of primitives
  92. // 1. the real one
  93. // 2. the wrapped one
  94. function primitives(value) {
  95. return value instanceof Primitive ? Primitive(value) : value;
  96. }
  97. function Primitives(key, value) {
  98. return typeof value === primitive ? new Primitive(value) : value;
  99. }
  100. }(String, 'string'));
  101. module.exports = Flatted;