index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. 'use strict';
  2. var _ansiStyles = require('ansi-styles');var _ansiStyles2 = _interopRequireDefault(_ansiStyles);
  3. var _collections = require('./collections');
  4. var _asymmetric_matcher = require('./plugins/asymmetric_matcher');var _asymmetric_matcher2 = _interopRequireDefault(_asymmetric_matcher);
  5. var _convert_ansi = require('./plugins/convert_ansi');var _convert_ansi2 = _interopRequireDefault(_convert_ansi);
  6. var _dom_element = require('./plugins/dom_element');var _dom_element2 = _interopRequireDefault(_dom_element);
  7. var _immutable = require('./plugins/immutable');var _immutable2 = _interopRequireDefault(_immutable);
  8. var _react_element = require('./plugins/react_element');var _react_element2 = _interopRequireDefault(_react_element);
  9. var _react_test_component = require('./plugins/react_test_component');var _react_test_component2 = _interopRequireDefault(_react_test_component);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };}
  10. const toString = Object.prototype.toString; /**
  11. * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  12. *
  13. * This source code is licensed under the MIT license found in the
  14. * LICENSE file in the root directory of this source tree.
  15. *
  16. *
  17. */const toISOString = Date.prototype.toISOString;const errorToString = Error.prototype.toString;const regExpToString = RegExp.prototype.toString;const symbolToString = Symbol.prototype.toString;const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;const NEWLINE_REGEXP = /\n/gi;
  18. function isToStringedArrayType(toStringed) {
  19. return (
  20. toStringed === '[object Array]' ||
  21. toStringed === '[object ArrayBuffer]' ||
  22. toStringed === '[object DataView]' ||
  23. toStringed === '[object Float32Array]' ||
  24. toStringed === '[object Float64Array]' ||
  25. toStringed === '[object Int8Array]' ||
  26. toStringed === '[object Int16Array]' ||
  27. toStringed === '[object Int32Array]' ||
  28. toStringed === '[object Uint8Array]' ||
  29. toStringed === '[object Uint8ClampedArray]' ||
  30. toStringed === '[object Uint16Array]' ||
  31. toStringed === '[object Uint32Array]');
  32. }
  33. function printNumber(val) {
  34. if (val != +val) {
  35. return 'NaN';
  36. }
  37. const isNegativeZero = val === 0 && 1 / val < 0;
  38. return isNegativeZero ? '-0' : '' + val;
  39. }
  40. function printFunction(val, printFunctionName) {
  41. if (!printFunctionName) {
  42. return '[Function]';
  43. }
  44. return '[Function ' + (val.name || 'anonymous') + ']';
  45. }
  46. function printSymbol(val) {
  47. return symbolToString.call(val).replace(SYMBOL_REGEXP, 'Symbol($1)');
  48. }
  49. function printError(val) {
  50. return '[' + errorToString.call(val) + ']';
  51. }
  52. function printBasicValue(
  53. val,
  54. printFunctionName,
  55. escapeRegex)
  56. {
  57. if (val === true || val === false) {
  58. return '' + val;
  59. }
  60. if (val === undefined) {
  61. return 'undefined';
  62. }
  63. if (val === null) {
  64. return 'null';
  65. }
  66. const typeOf = typeof val;
  67. if (typeOf === 'number') {
  68. return printNumber(val);
  69. }
  70. if (typeOf === 'string') {
  71. return '"' + val.replace(/"|\\/g, '\\$&') + '"';
  72. }
  73. if (typeOf === 'function') {
  74. return printFunction(val, printFunctionName);
  75. }
  76. if (typeOf === 'symbol') {
  77. return printSymbol(val);
  78. }
  79. const toStringed = toString.call(val);
  80. if (toStringed === '[object WeakMap]') {
  81. return 'WeakMap {}';
  82. }
  83. if (toStringed === '[object WeakSet]') {
  84. return 'WeakSet {}';
  85. }
  86. if (
  87. toStringed === '[object Function]' ||
  88. toStringed === '[object GeneratorFunction]')
  89. {
  90. return printFunction(val, printFunctionName);
  91. }
  92. if (toStringed === '[object Symbol]') {
  93. return printSymbol(val);
  94. }
  95. if (toStringed === '[object Date]') {
  96. return toISOString.call(val);
  97. }
  98. if (toStringed === '[object Error]') {
  99. return printError(val);
  100. }
  101. if (toStringed === '[object RegExp]') {
  102. if (escapeRegex) {
  103. // https://github.com/benjamingr/RegExp.escape/blob/master/polyfill.js
  104. return regExpToString.call(val).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
  105. }
  106. return regExpToString.call(val);
  107. }
  108. if (val instanceof Error) {
  109. return printError(val);
  110. }
  111. return null;
  112. }
  113. function printComplexValue(
  114. val,
  115. config,
  116. indentation,
  117. depth,
  118. refs)
  119. {
  120. if (refs.indexOf(val) !== -1) {
  121. return '[Circular]';
  122. }
  123. refs = refs.slice();
  124. refs.push(val);
  125. const hitMaxDepth = ++depth > config.maxDepth;
  126. const min = config.min;
  127. if (
  128. config.callToJSON &&
  129. !hitMaxDepth &&
  130. val.toJSON &&
  131. typeof val.toJSON === 'function')
  132. {
  133. return printer(val.toJSON(), config, indentation, depth, refs);
  134. }
  135. const toStringed = toString.call(val);
  136. if (toStringed === '[object Arguments]') {
  137. return hitMaxDepth ?
  138. '[Arguments]' :
  139. (min ? '' : 'Arguments ') +
  140. '[' +
  141. (0, _collections.printListItems)(val, config, indentation, depth, refs, printer) +
  142. ']';
  143. }
  144. if (isToStringedArrayType(toStringed)) {
  145. return hitMaxDepth ?
  146. '[' + val.constructor.name + ']' :
  147. (min ? '' : val.constructor.name + ' ') +
  148. '[' +
  149. (0, _collections.printListItems)(val, config, indentation, depth, refs, printer) +
  150. ']';
  151. }
  152. if (toStringed === '[object Map]') {
  153. return hitMaxDepth ?
  154. '[Map]' :
  155. 'Map {' +
  156. (0, _collections.printIteratorEntries)(
  157. val.entries(),
  158. config,
  159. indentation,
  160. depth,
  161. refs,
  162. printer,
  163. ' => ') +
  164. '}';
  165. }
  166. if (toStringed === '[object Set]') {
  167. return hitMaxDepth ?
  168. '[Set]' :
  169. 'Set {' +
  170. (0, _collections.printIteratorValues)(
  171. val.values(),
  172. config,
  173. indentation,
  174. depth,
  175. refs,
  176. printer) +
  177. '}';
  178. }
  179. return hitMaxDepth ?
  180. '[' + (val.constructor ? val.constructor.name : 'Object') + ']' :
  181. (min ? '' : (val.constructor ? val.constructor.name : 'Object') + ' ') +
  182. '{' +
  183. (0, _collections.printObjectProperties)(val, config, indentation, depth, refs, printer) +
  184. '}';
  185. }
  186. function printPlugin(
  187. plugin,
  188. val,
  189. config,
  190. indentation,
  191. depth,
  192. refs)
  193. {
  194. const printed = plugin.serialize ?
  195. plugin.serialize(val, config, indentation, depth, refs, printer) :
  196. plugin.print(
  197. val,
  198. valChild => printer(valChild, config, indentation, depth, refs),
  199. str => {
  200. const indentationNext = indentation + config.indent;
  201. return (
  202. indentationNext +
  203. str.replace(NEWLINE_REGEXP, '\n' + indentationNext));
  204. },
  205. {
  206. edgeSpacing: config.spacingOuter,
  207. min: config.min,
  208. spacing: config.spacingInner },
  209. config.colors);
  210. if (typeof printed !== 'string') {
  211. throw new Error(
  212. `pretty-format: Plugin must return type "string" but instead returned "${typeof printed}".`);
  213. }
  214. return printed;
  215. }
  216. function findPlugin(plugins, val) {
  217. for (let p = 0; p < plugins.length; p++) {
  218. if (plugins[p].test(val)) {
  219. return plugins[p];
  220. }
  221. }
  222. return null;
  223. }
  224. function printer(
  225. val,
  226. config,
  227. indentation,
  228. depth,
  229. refs)
  230. {
  231. const plugin = findPlugin(config.plugins, val);
  232. if (plugin !== null) {
  233. return printPlugin(plugin, val, config, indentation, depth, refs);
  234. }
  235. const basicResult = printBasicValue(
  236. val,
  237. config.printFunctionName,
  238. config.escapeRegex);
  239. if (basicResult !== null) {
  240. return basicResult;
  241. }
  242. return printComplexValue(val, config, indentation, depth, refs);
  243. }
  244. const DEFAULT_THEME = {
  245. comment: 'gray',
  246. content: 'reset',
  247. prop: 'yellow',
  248. tag: 'cyan',
  249. value: 'green' };
  250. const DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME);
  251. const DEFAULT_OPTIONS = {
  252. callToJSON: true,
  253. escapeRegex: false,
  254. highlight: false,
  255. indent: 2,
  256. maxDepth: Infinity,
  257. min: false,
  258. plugins: [],
  259. printFunctionName: true,
  260. theme: DEFAULT_THEME };
  261. function validateOptions(options) {
  262. Object.keys(options).forEach(key => {
  263. if (!DEFAULT_OPTIONS.hasOwnProperty(key)) {
  264. throw new Error(`pretty-format: Unknown option "${key}".`);
  265. }
  266. });
  267. if (options.min && options.indent !== undefined && options.indent !== 0) {
  268. throw new Error(
  269. 'pretty-format: Options "min" and "indent" cannot be used together.');
  270. }
  271. if (options.theme !== undefined) {
  272. if (options.theme === null) {
  273. throw new Error(`pretty-format: Option "theme" must not be null.`);
  274. }
  275. if (typeof options.theme !== 'object') {
  276. throw new Error(
  277. `pretty-format: Option "theme" must be of type "object" but instead received "${typeof options.theme}".`);
  278. }
  279. }
  280. }
  281. const getColorsHighlight = options =>
  282. DEFAULT_THEME_KEYS.reduce((colors, key) => {
  283. const value =
  284. options.theme && options.theme[key] !== undefined ?
  285. options.theme[key] :
  286. DEFAULT_THEME[key];
  287. const color = _ansiStyles2.default[value];
  288. if (
  289. color &&
  290. typeof color.close === 'string' &&
  291. typeof color.open === 'string')
  292. {
  293. colors[key] = color;
  294. } else {
  295. throw new Error(
  296. `pretty-format: Option "theme" has a key "${key}" whose value "${value}" is undefined in ansi-styles.`);
  297. }
  298. return colors;
  299. }, {});
  300. const getColorsEmpty = () =>
  301. DEFAULT_THEME_KEYS.reduce((colors, key) => {
  302. colors[key] = { close: '', open: '' };
  303. return colors;
  304. }, {});
  305. const getPrintFunctionName = options =>
  306. options && options.printFunctionName !== undefined ?
  307. options.printFunctionName :
  308. DEFAULT_OPTIONS.printFunctionName;
  309. const getEscapeRegex = options =>
  310. options && options.escapeRegex !== undefined ?
  311. options.escapeRegex :
  312. DEFAULT_OPTIONS.escapeRegex;
  313. const getConfig = options => ({
  314. callToJSON:
  315. options && options.callToJSON !== undefined ?
  316. options.callToJSON :
  317. DEFAULT_OPTIONS.callToJSON,
  318. colors:
  319. options && options.highlight ?
  320. getColorsHighlight(options) :
  321. getColorsEmpty(),
  322. escapeRegex: getEscapeRegex(options),
  323. indent:
  324. options && options.min ?
  325. '' :
  326. createIndent(
  327. options && options.indent !== undefined ?
  328. options.indent :
  329. DEFAULT_OPTIONS.indent),
  330. maxDepth:
  331. options && options.maxDepth !== undefined ?
  332. options.maxDepth :
  333. DEFAULT_OPTIONS.maxDepth,
  334. min: options && options.min !== undefined ? options.min : DEFAULT_OPTIONS.min,
  335. plugins:
  336. options && options.plugins !== undefined ?
  337. options.plugins :
  338. DEFAULT_OPTIONS.plugins,
  339. printFunctionName: getPrintFunctionName(options),
  340. spacingInner: options && options.min ? ' ' : '\n',
  341. spacingOuter: options && options.min ? '' : '\n' });
  342. function createIndent(indent) {
  343. return new Array(indent + 1).join(' ');
  344. }
  345. function prettyFormat(val, options) {
  346. if (options) {
  347. validateOptions(options);
  348. if (options.plugins) {
  349. const plugin = findPlugin(options.plugins, val);
  350. if (plugin !== null) {
  351. return printPlugin(plugin, val, getConfig(options), '', 0, []);
  352. }
  353. }
  354. }
  355. const basicResult = printBasicValue(
  356. val,
  357. getPrintFunctionName(options),
  358. getEscapeRegex(options));
  359. if (basicResult !== null) {
  360. return basicResult;
  361. }
  362. return printComplexValue(val, getConfig(options), '', 0, []);
  363. }
  364. prettyFormat.plugins = {
  365. AsymmetricMatcher: _asymmetric_matcher2.default,
  366. ConvertAnsi: _convert_ansi2.default,
  367. DOMElement: _dom_element2.default,
  368. Immutable: _immutable2.default,
  369. ReactElement: _react_element2.default,
  370. ReactTestComponent: _react_test_component2.default };
  371. module.exports = prettyFormat;