index.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /**
  2. * stringifier
  3. *
  4. * https://github.com/twada/stringifier
  5. *
  6. * Copyright (c) 2014-2018 Takuto Wada
  7. * Licensed under the MIT license.
  8. * https://twada.mit-license.org/2014-2018
  9. */
  10. 'use strict';
  11. var traverse = require('traverse');
  12. var typeName = require('type-name');
  13. var assign = require('core-js/library/fn/object/assign');
  14. var endsWith = require('core-js/library/fn/string/ends-with');
  15. var s = require('./strategies');
  16. function defaultHandlers () {
  17. return {
  18. 'null': s.always('null'),
  19. 'undefined': s.always('undefined'),
  20. 'function': s.prune(),
  21. 'string': s.json(),
  22. 'boolean': s.json(),
  23. 'number': s.number(),
  24. 'symbol': s.toStr(),
  25. 'RegExp': s.toStr(),
  26. 'String': s.newLike(),
  27. 'Boolean': s.newLike(),
  28. 'Number': s.newLike(),
  29. 'Date': s.newLike(),
  30. 'Array': s.array(),
  31. 'Object': s.object(),
  32. 'Error': s.object(null, ['message', 'code']),
  33. '@default': s.object()
  34. };
  35. }
  36. function defaultOptions () {
  37. return {
  38. maxDepth: null,
  39. indent: null,
  40. anonymous: '@Anonymous',
  41. circular: '#@Circular#',
  42. snip: '..(snip)',
  43. lineSeparator: '\n',
  44. typeFun: typeName
  45. };
  46. }
  47. function createStringifier (customOptions) {
  48. var options = assign({}, defaultOptions(), customOptions);
  49. var handlers = assign({}, defaultHandlers(), options.handlers);
  50. return function stringifyAny (push, x) {
  51. var context = this;
  52. var handler = handlerFor(context.node, options, handlers);
  53. var currentPath = '/' + context.path.join('/');
  54. var customization = handlers[currentPath];
  55. var acc = {
  56. context: context,
  57. options: options,
  58. handlers: handlers,
  59. push: push
  60. };
  61. if (typeName(customization) === 'function') {
  62. handler = customization;
  63. } else if (typeName(customization) === 'number') {
  64. handler = s.flow.compose(s.filters.truncate(customization),handler);
  65. } else if (context.parent && typeName(context.parent.node) === 'Array' && !(context.key in context.parent.node)) {
  66. // sparse arrays
  67. handler = s.always('');
  68. }
  69. handler(acc, x);
  70. return push;
  71. };
  72. }
  73. function handlerFor (val, options, handlers) {
  74. var tname = options.typeFun(val);
  75. if (typeName(handlers[tname]) === 'function') {
  76. return handlers[tname];
  77. }
  78. if (endsWith(tname, 'Error')) {
  79. return handlers['Error'];
  80. }
  81. return handlers['@default'];
  82. }
  83. function walk (val, reducer) {
  84. var buffer = [];
  85. var push = function (str) {
  86. buffer.push(str);
  87. };
  88. traverse(val).reduce(reducer, push);
  89. return buffer.join('');
  90. }
  91. function stringify (val, options) {
  92. return walk(val, createStringifier(options));
  93. }
  94. function stringifier (options) {
  95. return function (val) {
  96. return walk(val, createStringifier(options));
  97. };
  98. }
  99. stringifier.stringify = stringify;
  100. stringifier.strategies = s;
  101. stringifier.defaultOptions = defaultOptions;
  102. stringifier.defaultHandlers = defaultHandlers;
  103. module.exports = stringifier;