3 var _ansiStyles = require('ansi-styles');
5 var _ansiStyles2 = _interopRequireDefault(_ansiStyles);
7 var _collections = require('./collections');
9 var _asymmetric_matcher = require('./plugins/asymmetric_matcher');
11 var _asymmetric_matcher2 = _interopRequireDefault(_asymmetric_matcher);
13 var _convert_ansi = require('./plugins/convert_ansi');
15 var _convert_ansi2 = _interopRequireDefault(_convert_ansi);
17 var _dom_collection = require('./plugins/dom_collection');
19 var _dom_collection2 = _interopRequireDefault(_dom_collection);
21 var _dom_element = require('./plugins/dom_element');
23 var _dom_element2 = _interopRequireDefault(_dom_element);
25 var _immutable = require('./plugins/immutable');
27 var _immutable2 = _interopRequireDefault(_immutable);
29 var _react_element = require('./plugins/react_element');
31 var _react_element2 = _interopRequireDefault(_react_element);
33 var _react_test_component = require('./plugins/react_test_component');
35 var _react_test_component2 = _interopRequireDefault(_react_test_component);
37 function _interopRequireDefault(obj) {
38 return obj && obj.__esModule ? obj : {default: obj};
42 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
44 * This source code is licensed under the MIT license found in the
45 * LICENSE file in the root directory of this source tree.
50 const toString = Object.prototype.toString;
51 const toISOString = Date.prototype.toISOString;
52 const errorToString = Error.prototype.toString;
53 const regExpToString = RegExp.prototype.toString;
54 const symbolToString = Symbol.prototype.toString;
56 // Explicitly comparing typeof constructor to function avoids undefined as name
57 // when mock identity-obj-proxy returns the key as the value for any key.
58 const getConstructorName = val =>
59 (typeof val.constructor === 'function' && val.constructor.name) || 'Object';
61 // Is val is equal to global window object? Works even if it does not exist :)
63 const isWindow = val => typeof window !== 'undefined' && val === window;
65 const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;
66 const NEWLINE_REGEXP = /\n/gi;
68 class PrettyFormatPluginError extends Error {
69 constructor(message, stack) {
72 this.name = this.constructor.name;
76 function isToStringedArrayType(toStringed) {
78 toStringed === '[object Array]' ||
79 toStringed === '[object ArrayBuffer]' ||
80 toStringed === '[object DataView]' ||
81 toStringed === '[object Float32Array]' ||
82 toStringed === '[object Float64Array]' ||
83 toStringed === '[object Int8Array]' ||
84 toStringed === '[object Int16Array]' ||
85 toStringed === '[object Int32Array]' ||
86 toStringed === '[object Uint8Array]' ||
87 toStringed === '[object Uint8ClampedArray]' ||
88 toStringed === '[object Uint16Array]' ||
89 toStringed === '[object Uint32Array]'
93 function printNumber(val) {
94 return Object.is(val, -0) ? '-0' : String(val);
97 function printFunction(val, printFunctionName) {
98 if (!printFunctionName) {
101 return '[Function ' + (val.name || 'anonymous') + ']';
104 function printSymbol(val) {
105 return symbolToString.call(val).replace(SYMBOL_REGEXP, 'Symbol($1)');
108 function printError(val) {
109 return '[' + errorToString.call(val) + ']';
112 function printBasicValue(val, printFunctionName, escapeRegex) {
113 if (val === true || val === false) {
116 if (val === undefined) {
123 const typeOf = typeof val;
125 if (typeOf === 'number') {
126 return printNumber(val);
128 if (typeOf === 'string') {
129 return '"' + val.replace(/"|\\/g, '\\$&') + '"';
131 if (typeOf === 'function') {
132 return printFunction(val, printFunctionName);
134 if (typeOf === 'symbol') {
135 return printSymbol(val);
138 const toStringed = toString.call(val);
140 if (toStringed === '[object WeakMap]') {
143 if (toStringed === '[object WeakSet]') {
147 toStringed === '[object Function]' ||
148 toStringed === '[object GeneratorFunction]'
150 return printFunction(val, printFunctionName);
152 if (toStringed === '[object Symbol]') {
153 return printSymbol(val);
155 if (toStringed === '[object Date]') {
156 return isNaN(+val) ? 'Date { NaN }' : toISOString.call(val);
158 if (toStringed === '[object Error]') {
159 return printError(val);
161 if (toStringed === '[object RegExp]') {
163 // https://github.com/benjamingr/RegExp.escape/blob/master/polyfill.js
164 return regExpToString.call(val).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
166 return regExpToString.call(val);
169 if (val instanceof Error) {
170 return printError(val);
176 function printComplexValue(
184 if (refs.indexOf(val) !== -1) {
190 const hitMaxDepth = ++depth > config.maxDepth;
191 const min = config.min;
197 typeof val.toJSON === 'function' &&
200 return printer(val.toJSON(), config, indentation, depth, refs, true);
203 const toStringed = toString.call(val);
204 if (toStringed === '[object Arguments]') {
207 : (min ? '' : 'Arguments ') +
209 (0, _collections.printListItems)(
219 if (isToStringedArrayType(toStringed)) {
221 ? '[' + val.constructor.name + ']'
222 : (min ? '' : val.constructor.name + ' ') +
224 (0, _collections.printListItems)(
234 if (toStringed === '[object Map]') {
238 (0, _collections.printIteratorEntries)(
249 if (toStringed === '[object Set]') {
253 (0, _collections.printIteratorValues)(
264 // Avoid failure to serialize global window object in jsdom test environment.
265 // For example, not even relevant if window is prop of React element.
266 return hitMaxDepth || isWindow(val)
267 ? '[' + getConstructorName(val) + ']'
268 : (min ? '' : getConstructorName(val) + ' ') +
270 (0, _collections.printObjectProperties)(
281 function printPlugin(plugin, val, config, indentation, depth, refs) {
285 printed = plugin.serialize
286 ? plugin.serialize(val, config, indentation, depth, refs, printer)
289 valChild => printer(valChild, config, indentation, depth, refs),
291 const indentationNext = indentation + config.indent;
294 str.replace(NEWLINE_REGEXP, '\n' + indentationNext)
298 edgeSpacing: config.spacingOuter,
300 spacing: config.spacingInner
305 throw new PrettyFormatPluginError(error.message, error.stack);
307 if (typeof printed !== 'string') {
309 `pretty-format: Plugin must return type "string" but instead returned "${typeof printed}".`
315 function findPlugin(plugins, val) {
316 for (let p = 0; p < plugins.length; p++) {
318 if (plugins[p].test(val)) {
322 throw new PrettyFormatPluginError(error.message, error.stack);
329 function printer(val, config, indentation, depth, refs, hasCalledToJSON) {
330 const plugin = findPlugin(config.plugins, val);
331 if (plugin !== null) {
332 return printPlugin(plugin, val, config, indentation, depth, refs);
335 const basicResult = printBasicValue(
337 config.printFunctionName,
340 if (basicResult !== null) {
344 return printComplexValue(
354 const DEFAULT_THEME = {
362 const DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME);
364 const DEFAULT_OPTIONS = {
372 printFunctionName: true,
376 function validateOptions(options) {
377 Object.keys(options).forEach(key => {
378 if (!DEFAULT_OPTIONS.hasOwnProperty(key)) {
379 throw new Error(`pretty-format: Unknown option "${key}".`);
383 if (options.min && options.indent !== undefined && options.indent !== 0) {
385 'pretty-format: Options "min" and "indent" cannot be used together.'
389 if (options.theme !== undefined) {
390 if (options.theme === null) {
391 throw new Error(`pretty-format: Option "theme" must not be null.`);
394 if (typeof options.theme !== 'object') {
396 `pretty-format: Option "theme" must be of type "object" but instead received "${typeof options.theme}".`
402 const getColorsHighlight = (
404 // $FlowFixMe: Flow thinks keys from `Colors` are missing from `DEFAULT_THEME_KEYS`
406 DEFAULT_THEME_KEYS.reduce((colors, key) => {
408 options.theme && options.theme[key] !== undefined
410 : DEFAULT_THEME[key];
411 const color = _ansiStyles2.default[value];
414 typeof color.close === 'string' &&
415 typeof color.open === 'string'
420 `pretty-format: Option "theme" has a key "${key}" whose value "${value}" is undefined in ansi-styles.`
424 }, Object.create(null));
426 const getColorsEmpty = () =>
427 // $FlowFixMe: Flow thinks keys from `Colors` are missing from `DEFAULT_THEME_KEYS`
428 DEFAULT_THEME_KEYS.reduce((colors, key) => {
429 colors[key] = {close: '', open: ''};
431 }, Object.create(null));
433 const getPrintFunctionName = options =>
434 options && options.printFunctionName !== undefined
435 ? options.printFunctionName
436 : DEFAULT_OPTIONS.printFunctionName;
438 const getEscapeRegex = options =>
439 options && options.escapeRegex !== undefined
440 ? options.escapeRegex
441 : DEFAULT_OPTIONS.escapeRegex;
443 const getConfig = options => ({
445 options && options.callToJSON !== undefined
447 : DEFAULT_OPTIONS.callToJSON,
449 options && options.highlight
450 ? getColorsHighlight(options)
452 escapeRegex: getEscapeRegex(options),
454 options && options.min
457 options && options.indent !== undefined
459 : DEFAULT_OPTIONS.indent
462 options && options.maxDepth !== undefined
464 : DEFAULT_OPTIONS.maxDepth,
465 min: options && options.min !== undefined ? options.min : DEFAULT_OPTIONS.min,
467 options && options.plugins !== undefined
469 : DEFAULT_OPTIONS.plugins,
470 printFunctionName: getPrintFunctionName(options),
471 spacingInner: options && options.min ? ' ' : '\n',
472 spacingOuter: options && options.min ? '' : '\n'
475 function createIndent(indent) {
476 return new Array(indent + 1).join(' ');
479 function prettyFormat(val, options) {
481 validateOptions(options);
482 if (options.plugins) {
483 const plugin = findPlugin(options.plugins, val);
484 if (plugin !== null) {
485 return printPlugin(plugin, val, getConfig(options), '', 0, []);
490 const basicResult = printBasicValue(
492 getPrintFunctionName(options),
493 getEscapeRegex(options)
495 if (basicResult !== null) {
499 return printComplexValue(val, getConfig(options), '', 0, []);
502 prettyFormat.plugins = {
503 AsymmetricMatcher: _asymmetric_matcher2.default,
504 ConvertAnsi: _convert_ansi2.default,
505 DOMCollection: _dom_collection2.default,
506 DOMElement: _dom_element2.default,
507 Immutable: _immutable2.default,
508 ReactElement: _react_element2.default,
509 ReactTestComponent: _react_test_component2.default
512 module.exports = prettyFormat;