| 'use strict'; |
| |
| var _ansiStyles = _interopRequireDefault(require('ansi-styles')); |
| |
| var _collections = require('./collections'); |
| |
| var _AsymmetricMatcher = _interopRequireDefault( |
| require('./plugins/AsymmetricMatcher') |
| ); |
| |
| var _ConvertAnsi = _interopRequireDefault(require('./plugins/ConvertAnsi')); |
| |
| var _DOMCollection = _interopRequireDefault(require('./plugins/DOMCollection')); |
| |
| var _DOMElement = _interopRequireDefault(require('./plugins/DOMElement')); |
| |
| var _Immutable = _interopRequireDefault(require('./plugins/Immutable')); |
| |
| var _ReactElement = _interopRequireDefault(require('./plugins/ReactElement')); |
| |
| var _ReactTestComponent = _interopRequireDefault( |
| require('./plugins/ReactTestComponent') |
| ); |
| |
| function _interopRequireDefault(obj) { |
| return obj && obj.__esModule ? obj : {default: obj}; |
| } |
| |
| /** |
| * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. |
| * |
| * This source code is licensed under the MIT license found in the |
| * LICENSE file in the root directory of this source tree. |
| */ |
| |
| /* eslint-disable local/ban-types-eventually */ |
| const toString = Object.prototype.toString; |
| const toISOString = Date.prototype.toISOString; |
| const errorToString = Error.prototype.toString; |
| const regExpToString = RegExp.prototype.toString; |
| /** |
| * Explicitly comparing typeof constructor to function avoids undefined as name |
| * when mock identity-obj-proxy returns the key as the value for any key. |
| */ |
| |
| const getConstructorName = val => |
| (typeof val.constructor === 'function' && val.constructor.name) || 'Object'; |
| /* global window */ |
| |
| /** Is val is equal to global window object? Works even if it does not exist :) */ |
| |
| const isWindow = val => typeof window !== 'undefined' && val === window; |
| |
| const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/; |
| const NEWLINE_REGEXP = /\n/gi; |
| |
| class PrettyFormatPluginError extends Error { |
| constructor(message, stack) { |
| super(message); |
| this.stack = stack; |
| this.name = this.constructor.name; |
| } |
| } |
| |
| function isToStringedArrayType(toStringed) { |
| return ( |
| toStringed === '[object Array]' || |
| toStringed === '[object ArrayBuffer]' || |
| toStringed === '[object DataView]' || |
| toStringed === '[object Float32Array]' || |
| toStringed === '[object Float64Array]' || |
| toStringed === '[object Int8Array]' || |
| toStringed === '[object Int16Array]' || |
| toStringed === '[object Int32Array]' || |
| toStringed === '[object Uint8Array]' || |
| toStringed === '[object Uint8ClampedArray]' || |
| toStringed === '[object Uint16Array]' || |
| toStringed === '[object Uint32Array]' |
| ); |
| } |
| |
| function printNumber(val) { |
| return Object.is(val, -0) ? '-0' : String(val); |
| } |
| |
| function printBigInt(val) { |
| return String(`${val}n`); |
| } |
| |
| function printFunction(val, printFunctionName) { |
| if (!printFunctionName) { |
| return '[Function]'; |
| } |
| |
| return '[Function ' + (val.name || 'anonymous') + ']'; |
| } |
| |
| function printSymbol(val) { |
| return String(val).replace(SYMBOL_REGEXP, 'Symbol($1)'); |
| } |
| |
| function printError(val) { |
| return '[' + errorToString.call(val) + ']'; |
| } |
| /** |
| * The first port of call for printing an object, handles most of the |
| * data-types in JS. |
| */ |
| |
| function printBasicValue(val, printFunctionName, escapeRegex, escapeString) { |
| if (val === true || val === false) { |
| return '' + val; |
| } |
| |
| if (val === undefined) { |
| return 'undefined'; |
| } |
| |
| if (val === null) { |
| return 'null'; |
| } |
| |
| const typeOf = typeof val; |
| |
| if (typeOf === 'number') { |
| return printNumber(val); |
| } |
| |
| if (typeOf === 'bigint') { |
| return printBigInt(val); |
| } |
| |
| if (typeOf === 'string') { |
| if (escapeString) { |
| return '"' + val.replace(/"|\\/g, '\\$&') + '"'; |
| } |
| |
| return '"' + val + '"'; |
| } |
| |
| if (typeOf === 'function') { |
| return printFunction(val, printFunctionName); |
| } |
| |
| if (typeOf === 'symbol') { |
| return printSymbol(val); |
| } |
| |
| const toStringed = toString.call(val); |
| |
| if (toStringed === '[object WeakMap]') { |
| return 'WeakMap {}'; |
| } |
| |
| if (toStringed === '[object WeakSet]') { |
| return 'WeakSet {}'; |
| } |
| |
| if ( |
| toStringed === '[object Function]' || |
| toStringed === '[object GeneratorFunction]' |
| ) { |
| return printFunction(val, printFunctionName); |
| } |
| |
| if (toStringed === '[object Symbol]') { |
| return printSymbol(val); |
| } |
| |
| if (toStringed === '[object Date]') { |
| return isNaN(+val) ? 'Date { NaN }' : toISOString.call(val); |
| } |
| |
| if (toStringed === '[object Error]') { |
| return printError(val); |
| } |
| |
| if (toStringed === '[object RegExp]') { |
| if (escapeRegex) { |
| // https://github.com/benjamingr/RegExp.escape/blob/master/polyfill.js |
| return regExpToString.call(val).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&'); |
| } |
| |
| return regExpToString.call(val); |
| } |
| |
| if (val instanceof Error) { |
| return printError(val); |
| } |
| |
| return null; |
| } |
| /** |
| * Handles more complex objects ( such as objects with circular references. |
| * maps and sets etc ) |
| */ |
| |
| function printComplexValue( |
| val, |
| config, |
| indentation, |
| depth, |
| refs, |
| hasCalledToJSON |
| ) { |
| if (refs.indexOf(val) !== -1) { |
| return '[Circular]'; |
| } |
| |
| refs = refs.slice(); |
| refs.push(val); |
| const hitMaxDepth = ++depth > config.maxDepth; |
| const min = config.min; |
| |
| if ( |
| config.callToJSON && |
| !hitMaxDepth && |
| val.toJSON && |
| typeof val.toJSON === 'function' && |
| !hasCalledToJSON |
| ) { |
| return printer(val.toJSON(), config, indentation, depth, refs, true); |
| } |
| |
| const toStringed = toString.call(val); |
| |
| if (toStringed === '[object Arguments]') { |
| return hitMaxDepth |
| ? '[Arguments]' |
| : (min ? '' : 'Arguments ') + |
| '[' + |
| (0, _collections.printListItems)( |
| val, |
| config, |
| indentation, |
| depth, |
| refs, |
| printer |
| ) + |
| ']'; |
| } |
| |
| if (isToStringedArrayType(toStringed)) { |
| return hitMaxDepth |
| ? '[' + val.constructor.name + ']' |
| : (min ? '' : val.constructor.name + ' ') + |
| '[' + |
| (0, _collections.printListItems)( |
| val, |
| config, |
| indentation, |
| depth, |
| refs, |
| printer |
| ) + |
| ']'; |
| } |
| |
| if (toStringed === '[object Map]') { |
| return hitMaxDepth |
| ? '[Map]' |
| : 'Map {' + |
| (0, _collections.printIteratorEntries)( |
| val.entries(), |
| config, |
| indentation, |
| depth, |
| refs, |
| printer, |
| ' => ' |
| ) + |
| '}'; |
| } |
| |
| if (toStringed === '[object Set]') { |
| return hitMaxDepth |
| ? '[Set]' |
| : 'Set {' + |
| (0, _collections.printIteratorValues)( |
| val.values(), |
| config, |
| indentation, |
| depth, |
| refs, |
| printer |
| ) + |
| '}'; |
| } // Avoid failure to serialize global window object in jsdom test environment. |
| // For example, not even relevant if window is prop of React element. |
| |
| return hitMaxDepth || isWindow(val) |
| ? '[' + getConstructorName(val) + ']' |
| : (min ? '' : getConstructorName(val) + ' ') + |
| '{' + |
| (0, _collections.printObjectProperties)( |
| val, |
| config, |
| indentation, |
| depth, |
| refs, |
| printer |
| ) + |
| '}'; |
| } |
| |
| function isNewPlugin(plugin) { |
| return plugin.serialize != null; |
| } |
| |
| function printPlugin(plugin, val, config, indentation, depth, refs) { |
| let printed; |
| |
| try { |
| printed = isNewPlugin(plugin) |
| ? plugin.serialize(val, config, indentation, depth, refs, printer) |
| : plugin.print( |
| val, |
| valChild => printer(valChild, config, indentation, depth, refs), |
| str => { |
| const indentationNext = indentation + config.indent; |
| return ( |
| indentationNext + |
| str.replace(NEWLINE_REGEXP, '\n' + indentationNext) |
| ); |
| }, |
| { |
| edgeSpacing: config.spacingOuter, |
| min: config.min, |
| spacing: config.spacingInner |
| }, |
| config.colors |
| ); |
| } catch (error) { |
| throw new PrettyFormatPluginError(error.message, error.stack); |
| } |
| |
| if (typeof printed !== 'string') { |
| throw new Error( |
| `pretty-format: Plugin must return type "string" but instead returned "${typeof printed}".` |
| ); |
| } |
| |
| return printed; |
| } |
| |
| function findPlugin(plugins, val) { |
| for (let p = 0; p < plugins.length; p++) { |
| try { |
| if (plugins[p].test(val)) { |
| return plugins[p]; |
| } |
| } catch (error) { |
| throw new PrettyFormatPluginError(error.message, error.stack); |
| } |
| } |
| |
| return null; |
| } |
| |
| function printer(val, config, indentation, depth, refs, hasCalledToJSON) { |
| const plugin = findPlugin(config.plugins, val); |
| |
| if (plugin !== null) { |
| return printPlugin(plugin, val, config, indentation, depth, refs); |
| } |
| |
| const basicResult = printBasicValue( |
| val, |
| config.printFunctionName, |
| config.escapeRegex, |
| config.escapeString |
| ); |
| |
| if (basicResult !== null) { |
| return basicResult; |
| } |
| |
| return printComplexValue( |
| val, |
| config, |
| indentation, |
| depth, |
| refs, |
| hasCalledToJSON |
| ); |
| } |
| |
| const DEFAULT_THEME = { |
| comment: 'gray', |
| content: 'reset', |
| prop: 'yellow', |
| tag: 'cyan', |
| value: 'green' |
| }; |
| const DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME); |
| const DEFAULT_OPTIONS = { |
| callToJSON: true, |
| escapeRegex: false, |
| escapeString: true, |
| highlight: false, |
| indent: 2, |
| maxDepth: Infinity, |
| min: false, |
| plugins: [], |
| printFunctionName: true, |
| theme: DEFAULT_THEME |
| }; |
| |
| function validateOptions(options) { |
| Object.keys(options).forEach(key => { |
| if (!DEFAULT_OPTIONS.hasOwnProperty(key)) { |
| throw new Error(`pretty-format: Unknown option "${key}".`); |
| } |
| }); |
| |
| if (options.min && options.indent !== undefined && options.indent !== 0) { |
| throw new Error( |
| 'pretty-format: Options "min" and "indent" cannot be used together.' |
| ); |
| } |
| |
| if (options.theme !== undefined) { |
| if (options.theme === null) { |
| throw new Error(`pretty-format: Option "theme" must not be null.`); |
| } |
| |
| if (typeof options.theme !== 'object') { |
| throw new Error( |
| `pretty-format: Option "theme" must be of type "object" but instead received "${typeof options.theme}".` |
| ); |
| } |
| } |
| } |
| |
| const getColorsHighlight = options => |
| DEFAULT_THEME_KEYS.reduce((colors, key) => { |
| const value = |
| options.theme && options.theme[key] !== undefined |
| ? options.theme[key] |
| : DEFAULT_THEME[key]; |
| const color = value && _ansiStyles.default[value]; |
| |
| if ( |
| color && |
| typeof color.close === 'string' && |
| typeof color.open === 'string' |
| ) { |
| colors[key] = color; |
| } else { |
| throw new Error( |
| `pretty-format: Option "theme" has a key "${key}" whose value "${value}" is undefined in ansi-styles.` |
| ); |
| } |
| |
| return colors; |
| }, Object.create(null)); |
| |
| const getColorsEmpty = () => |
| DEFAULT_THEME_KEYS.reduce((colors, key) => { |
| colors[key] = { |
| close: '', |
| open: '' |
| }; |
| return colors; |
| }, Object.create(null)); |
| |
| const getPrintFunctionName = options => |
| options && options.printFunctionName !== undefined |
| ? options.printFunctionName |
| : DEFAULT_OPTIONS.printFunctionName; |
| |
| const getEscapeRegex = options => |
| options && options.escapeRegex !== undefined |
| ? options.escapeRegex |
| : DEFAULT_OPTIONS.escapeRegex; |
| |
| const getEscapeString = options => |
| options && options.escapeString !== undefined |
| ? options.escapeString |
| : DEFAULT_OPTIONS.escapeString; |
| |
| const getConfig = options => ({ |
| callToJSON: |
| options && options.callToJSON !== undefined |
| ? options.callToJSON |
| : DEFAULT_OPTIONS.callToJSON, |
| colors: |
| options && options.highlight |
| ? getColorsHighlight(options) |
| : getColorsEmpty(), |
| escapeRegex: getEscapeRegex(options), |
| escapeString: getEscapeString(options), |
| indent: |
| options && options.min |
| ? '' |
| : createIndent( |
| options && options.indent !== undefined |
| ? options.indent |
| : DEFAULT_OPTIONS.indent |
| ), |
| maxDepth: |
| options && options.maxDepth !== undefined |
| ? options.maxDepth |
| : DEFAULT_OPTIONS.maxDepth, |
| min: options && options.min !== undefined ? options.min : DEFAULT_OPTIONS.min, |
| plugins: |
| options && options.plugins !== undefined |
| ? options.plugins |
| : DEFAULT_OPTIONS.plugins, |
| printFunctionName: getPrintFunctionName(options), |
| spacingInner: options && options.min ? ' ' : '\n', |
| spacingOuter: options && options.min ? '' : '\n' |
| }); |
| |
| function createIndent(indent) { |
| return new Array(indent + 1).join(' '); |
| } |
| /** |
| * Returns a presentation string of your `val` object |
| * @param val any potential JavaScript object |
| * @param options Custom settings |
| */ |
| |
| function prettyFormat(val, options) { |
| if (options) { |
| validateOptions(options); |
| |
| if (options.plugins) { |
| const plugin = findPlugin(options.plugins, val); |
| |
| if (plugin !== null) { |
| return printPlugin(plugin, val, getConfig(options), '', 0, []); |
| } |
| } |
| } |
| |
| const basicResult = printBasicValue( |
| val, |
| getPrintFunctionName(options), |
| getEscapeRegex(options), |
| getEscapeString(options) |
| ); |
| |
| if (basicResult !== null) { |
| return basicResult; |
| } |
| |
| return printComplexValue(val, getConfig(options), '', 0, []); |
| } |
| |
| prettyFormat.plugins = { |
| AsymmetricMatcher: _AsymmetricMatcher.default, |
| ConvertAnsi: _ConvertAnsi.default, |
| DOMCollection: _DOMCollection.default, |
| DOMElement: _DOMElement.default, |
| Immutable: _Immutable.default, |
| ReactElement: _ReactElement.default, |
| ReactTestComponent: _ReactTestComponent.default |
| }; |
| module.exports = prettyFormat; |