index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. // this was invoking twice each root object
  46. // return i < 1 ? value : $.call(this, key, value);
  47. }
  48. var after = $.call(this, key, value);
  49. switch (typeof after) {
  50. case 'object':
  51. if (after === null) return after;
  52. case primitive:
  53. return known.get(after) || set(known, input, after);
  54. }
  55. return after;
  56. };
  57. i < input.length; i++
  58. ) {
  59. firstRun = true;
  60. output[i] = JSON.stringify(input[i], replace, space);
  61. }
  62. return '[' + output.join(',') + ']';
  63. }
  64. };
  65. return Flatted;
  66. function noop(key, value) {
  67. return value;
  68. }
  69. function revive(input, parsed, output, $) {
  70. return Object.keys(output).reduce(
  71. function (output, key) {
  72. var value = output[key];
  73. if (value instanceof Primitive) {
  74. var tmp = input[value];
  75. if (typeof tmp === 'object' && !parsed.has(tmp)) {
  76. parsed.add(tmp);
  77. output[key] = $.call(output, key, revive(input, parsed, tmp, $));
  78. } else {
  79. output[key] = $.call(output, key, tmp);
  80. }
  81. } else
  82. output[key] = $.call(output, key, value);
  83. return output;
  84. },
  85. output
  86. );
  87. }
  88. function set(known, input, value) {
  89. var index = Primitive(input.push(value) - 1);
  90. known.set(value, index);
  91. return index;
  92. }
  93. // the two kinds of primitives
  94. // 1. the real one
  95. // 2. the wrapped one
  96. function primitives(value) {
  97. return value instanceof Primitive ? Primitive(value) : value;
  98. }
  99. function Primitives(key, value) {
  100. return typeof value === primitive ? new Primitive(value) : value;
  101. }
  102. }(String, 'string'));