plotly.js
Version:
The open source javascript graphing library that powers plotly
1,670 lines (1,403 loc) • 3.89 MB
JavaScript
/**
* plotly.js (gl2d) v1.58.4
* Copyright 2012-2020, Plotly, Inc.
* All rights reserved.
* Licensed under the MIT license
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Plotly = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(_dereq_,module,exports){
'use strict';
var Lib = _dereq_('../src/lib');
var rules = {
"X,X div": "direction:ltr;font-family:'Open Sans', verdana, arial, sans-serif;margin:0;padding:0;",
"X input,X button": "font-family:'Open Sans', verdana, arial, sans-serif;",
"X input:focus,X button:focus": "outline:none;",
"X a": "text-decoration:none;",
"X a:hover": "text-decoration:none;",
"X .crisp": "shape-rendering:crispEdges;",
"X .user-select-none": "-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;",
"X svg": "overflow:hidden;",
"X svg a": "fill:#447adb;",
"X svg a:hover": "fill:#3c6dc5;",
"X .main-svg": "position:absolute;top:0;left:0;pointer-events:none;",
"X .main-svg .draglayer": "pointer-events:all;",
"X .cursor-default": "cursor:default;",
"X .cursor-pointer": "cursor:pointer;",
"X .cursor-crosshair": "cursor:crosshair;",
"X .cursor-move": "cursor:move;",
"X .cursor-col-resize": "cursor:col-resize;",
"X .cursor-row-resize": "cursor:row-resize;",
"X .cursor-ns-resize": "cursor:ns-resize;",
"X .cursor-ew-resize": "cursor:ew-resize;",
"X .cursor-sw-resize": "cursor:sw-resize;",
"X .cursor-s-resize": "cursor:s-resize;",
"X .cursor-se-resize": "cursor:se-resize;",
"X .cursor-w-resize": "cursor:w-resize;",
"X .cursor-e-resize": "cursor:e-resize;",
"X .cursor-nw-resize": "cursor:nw-resize;",
"X .cursor-n-resize": "cursor:n-resize;",
"X .cursor-ne-resize": "cursor:ne-resize;",
"X .cursor-grab": "cursor:-webkit-grab;cursor:grab;",
"X .modebar": "position:absolute;top:2px;right:2px;",
"X .ease-bg": "-webkit-transition:background-color 0.3s ease 0s;-moz-transition:background-color 0.3s ease 0s;-ms-transition:background-color 0.3s ease 0s;-o-transition:background-color 0.3s ease 0s;transition:background-color 0.3s ease 0s;",
"X .modebar--hover>:not(.watermark)": "opacity:0;-webkit-transition:opacity 0.3s ease 0s;-moz-transition:opacity 0.3s ease 0s;-ms-transition:opacity 0.3s ease 0s;-o-transition:opacity 0.3s ease 0s;transition:opacity 0.3s ease 0s;",
"X:hover .modebar--hover .modebar-group": "opacity:1;",
"X .modebar-group": "float:left;display:inline-block;box-sizing:border-box;padding-left:8px;position:relative;vertical-align:middle;white-space:nowrap;",
"X .modebar-btn": "position:relative;font-size:16px;padding:3px 4px;height:22px;cursor:pointer;line-height:normal;box-sizing:border-box;",
"X .modebar-btn svg": "position:relative;top:2px;",
"X .modebar.vertical": "display:flex;flex-direction:column;flex-wrap:wrap;align-content:flex-end;max-height:100%;",
"X .modebar.vertical svg": "top:-1px;",
"X .modebar.vertical .modebar-group": "display:block;float:none;padding-left:0px;padding-bottom:8px;",
"X .modebar.vertical .modebar-group .modebar-btn": "display:block;text-align:center;",
"X [data-title]:before,X [data-title]:after": "position:absolute;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);-ms-transform:translate3d(0, 0, 0);-o-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);display:none;opacity:0;z-index:1001;pointer-events:none;top:110%;right:50%;",
"X [data-title]:hover:before,X [data-title]:hover:after": "display:block;opacity:1;",
"X [data-title]:before": "content:'';position:absolute;background:transparent;border:6px solid transparent;z-index:1002;margin-top:-12px;border-bottom-color:#69738a;margin-right:-6px;",
"X [data-title]:after": "content:attr(data-title);background:#69738a;color:white;padding:8px 10px;font-size:12px;line-height:12px;white-space:nowrap;margin-right:-18px;border-radius:2px;",
"X .vertical [data-title]:before,X .vertical [data-title]:after": "top:0%;right:200%;",
"X .vertical [data-title]:before": "border:6px solid transparent;border-left-color:#69738a;margin-top:8px;margin-right:-30px;",
"X .select-outline": "fill:none;stroke-width:1;shape-rendering:crispEdges;",
"X .select-outline-1": "stroke:white;",
"X .select-outline-2": "stroke:black;stroke-dasharray:2px 2px;",
Y: "font-family:'Open Sans', verdana, arial, sans-serif;position:fixed;top:50px;right:20px;z-index:10000;font-size:10pt;max-width:180px;",
"Y p": "margin:0;",
"Y .notifier-note": "min-width:180px;max-width:250px;border:1px solid #fff;z-index:3000;margin:0;background-color:#8c97af;background-color:rgba(140,151,175,0.9);color:#fff;padding:10px;overflow-wrap:break-word;word-wrap:break-word;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;",
"Y .notifier-close": "color:#fff;opacity:0.8;float:right;padding:0 5px;background:none;border:none;font-size:20px;font-weight:bold;line-height:20px;",
"Y .notifier-close:hover": "color:#444;text-decoration:none;cursor:pointer;"
};
for(var selector in rules) {
var fullSelector = selector.replace(/^,/,' ,')
.replace(/X/g, '.js-plotly-plot .plotly')
.replace(/Y/g, '.plotly-notifier');
Lib.addStyleRule(fullSelector, rules[selector]);
}
},{"../src/lib":498}],2:[function(_dereq_,module,exports){
/**
* Copyright 2012-2020, Plotly, Inc.
* 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.
*/
'use strict';
module.exports = _dereq_('../src/traces/contourgl');
},{"../src/traces/contourgl":615}],3:[function(_dereq_,module,exports){
/**
* Copyright 2012-2020, Plotly, Inc.
* 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.
*/
'use strict';
module.exports = _dereq_('../src/core');
},{"../src/core":477}],4:[function(_dereq_,module,exports){
/**
* Copyright 2012-2020, Plotly, Inc.
* 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.
*/
'use strict';
module.exports = _dereq_('../src/traces/heatmapgl');
},{"../src/traces/heatmapgl":628}],5:[function(_dereq_,module,exports){
/**
* Copyright 2012-2020, Plotly, Inc.
* 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.
*/
'use strict';
var Plotly = _dereq_('./core');
Plotly.register([
_dereq_('./scattergl'),
_dereq_('./splom'),
_dereq_('./pointcloud'),
_dereq_('./heatmapgl'),
_dereq_('./contourgl'),
_dereq_('./parcoords')
]);
module.exports = Plotly;
},{"./contourgl":2,"./core":3,"./heatmapgl":4,"./parcoords":6,"./pointcloud":7,"./scattergl":8,"./splom":9}],6:[function(_dereq_,module,exports){
/**
* Copyright 2012-2020, Plotly, Inc.
* 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.
*/
'use strict';
module.exports = _dereq_('../src/traces/parcoords');
},{"../src/traces/parcoords":642}],7:[function(_dereq_,module,exports){
/**
* Copyright 2012-2020, Plotly, Inc.
* 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.
*/
'use strict';
module.exports = _dereq_('../src/traces/pointcloud');
},{"../src/traces/pointcloud":652}],8:[function(_dereq_,module,exports){
/**
* Copyright 2012-2020, Plotly, Inc.
* 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.
*/
'use strict';
module.exports = _dereq_('../src/traces/scattergl');
},{"../src/traces/scattergl":692}],9:[function(_dereq_,module,exports){
/**
* Copyright 2012-2020, Plotly, Inc.
* 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.
*/
'use strict';
module.exports = _dereq_('../src/traces/splom');
},{"../src/traces/splom":703}],10:[function(_dereq_,module,exports){
'use strict'
module.exports = _dereq_('./quad')
},{"./quad":11}],11:[function(_dereq_,module,exports){
/**
* @module point-cluster/quad
*
* Bucket based quad tree clustering
*/
'use strict'
var search = _dereq_('binary-search-bounds')
var clamp = _dereq_('clamp')
var rect = _dereq_('parse-rect')
var getBounds = _dereq_('array-bounds')
var pick = _dereq_('pick-by-alias')
var defined = _dereq_('defined')
var flatten = _dereq_('flatten-vertex-data')
var isObj = _dereq_('is-obj')
var dtype = _dereq_('dtype')
var log2 = _dereq_('math-log2')
var MAX_GROUP_ID = 1073741824
module.exports = function cluster (srcPoints, options) {
if (!options) { options = {} }
srcPoints = flatten(srcPoints, 'float64')
options = pick(options, {
bounds: 'range bounds dataBox databox',
maxDepth: 'depth maxDepth maxdepth level maxLevel maxlevel levels',
dtype: 'type dtype format out dst output destination'
// sort: 'sortBy sortby sort',
// pick: 'pick levelPoint',
// nodeSize: 'node nodeSize minNodeSize minSize size'
})
// let nodeSize = defined(options.nodeSize, 1)
var maxDepth = defined(options.maxDepth, 255)
var bounds = defined(options.bounds, getBounds(srcPoints, 2))
if (bounds[0] === bounds[2]) { bounds[2]++ }
if (bounds[1] === bounds[3]) { bounds[3]++ }
var points = normalize(srcPoints, bounds)
// init variables
var n = srcPoints.length >>> 1
var ids
if (!options.dtype) { options.dtype = 'array' }
if (typeof options.dtype === 'string') {
ids = new (dtype(options.dtype))(n)
}
else if (options.dtype) {
ids = options.dtype
if (Array.isArray(ids)) { ids.length = n }
}
for (var i = 0; i < n; ++i) {
ids[i] = i
}
// representative point indexes for levels
var levels = []
// starting indexes of subranges in sub levels, levels.length * 4
var sublevels = []
// unique group ids, sorted in z-curve fashion within levels by shifting bits
var groups = []
// level offsets in `ids`
var offsets = []
// sort points
sort(0, 0, 1, ids, 0, 1)
// return reordered ids with provided methods
// save level offsets in output buffer
var offset = 0
for (var level = 0; level < levels.length; level++) {
var levelItems = levels[level]
if (ids.set) { ids.set(levelItems, offset) }
else {
for (var i$1 = 0, l = levelItems.length; i$1 < l; i$1++) {
ids[i$1 + offset] = levelItems[i$1]
}
}
var nextOffset = offset + levels[level].length
offsets[level] = [offset, nextOffset]
offset = nextOffset
}
ids.range = range
return ids
// FIXME: it is possible to create one typed array heap and reuse that to avoid memory blow
function sort (x, y, diam, ids, level, group) {
if (!ids.length) { return null }
// save first point as level representative
var levelItems = levels[level] || (levels[level] = [])
var levelGroups = groups[level] || (groups[level] = [])
var sublevel = sublevels[level] || (sublevels[level] = [])
var offset = levelItems.length
level++
// max depth reached - put all items into a first group
// alternatively - if group id overflow - avoid proceeding
if (level > maxDepth || group > MAX_GROUP_ID) {
for (var i = 0; i < ids.length; i++) {
levelItems.push(ids[i])
levelGroups.push(group)
sublevel.push(null, null, null, null)
}
return offset
}
levelItems.push(ids[0])
levelGroups.push(group)
if (ids.length <= 1) {
sublevel.push(null, null, null, null)
return offset
}
var d2 = diam * .5
var cx = x + d2, cy = y + d2
// distribute points by 4 buckets
var lolo = [], lohi = [], hilo = [], hihi = []
for (var i$1 = 1, l = ids.length; i$1 < l; i$1++) {
var idx = ids[i$1],
x$1 = points[idx * 2],
y$1 = points[idx * 2 + 1]
x$1 < cx ? (y$1 < cy ? lolo.push(idx) : lohi.push(idx)) : (y$1 < cy ? hilo.push(idx) : hihi.push(idx))
}
group <<= 2
sublevel.push(
sort(x, y, d2, lolo, level, group),
sort(x, cy, d2, lohi, level, group + 1),
sort(cx, y, d2, hilo, level, group + 2),
sort(cx, cy, d2, hihi, level, group + 3)
)
return offset
}
// get all points within the passed range
function range () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
var options
if (isObj(args[args.length - 1])) {
var arg = args.pop()
// detect if that was a rect object
if (!args.length && (arg.x != null || arg.l != null || arg.left != null)) {
args = [arg]
options = {}
}
options = pick(arg, {
level: 'level maxLevel',
d: 'd diam diameter r radius px pxSize pixel pixelSize maxD size minSize',
lod: 'lod details ranges offsets'
})
}
else {
options = {}
}
if (!args.length) { args = bounds }
var box = rect.apply( void 0, args )
var ref = [
Math.min(box.x, box.x + box.width),
Math.min(box.y, box.y + box.height),
Math.max(box.x, box.x + box.width),
Math.max(box.y, box.y + box.height)
];
var minX = ref[0];
var minY = ref[1];
var maxX = ref[2];
var maxY = ref[3];
var ref$1 = normalize([minX, minY, maxX, maxY], bounds );
var nminX = ref$1[0];
var nminY = ref$1[1];
var nmaxX = ref$1[2];
var nmaxY = ref$1[3];
var maxLevel = defined(options.level, levels.length)
// limit maxLevel by px size
if (options.d != null) {
var d
if (typeof options.d === 'number') { d = [options.d, options.d] }
else if (options.d.length) { d = options.d }
maxLevel = Math.min(
Math.max(
Math.ceil(-log2(Math.abs(d[0]) / (bounds[2] - bounds[0]))),
Math.ceil(-log2(Math.abs(d[1]) / (bounds[3] - bounds[1])))
),
maxLevel
)
}
maxLevel = Math.min(maxLevel, levels.length)
// return levels of details
if (options.lod) {
return lod(nminX, nminY, nmaxX, nmaxY, maxLevel)
}
// do selection ids
var selection = []
// FIXME: probably we can do LOD here beforehead
select( 0, 0, 1, 0, 0, 1)
function select ( lox, loy, d, level, from, to ) {
if (from === null || to === null) { return }
var hix = lox + d
var hiy = loy + d
// if box does not intersect level - ignore
if ( nminX > hix || nminY > hiy || nmaxX < lox || nmaxY < loy ) { return }
if ( level >= maxLevel ) { return }
if ( from === to ) { return }
// if points fall into box range - take it
var levelItems = levels[level]
if (to === undefined) { to = levelItems.length }
for (var i = from; i < to; i++) {
var id = levelItems[i]
var px = srcPoints[ id * 2 ]
var py = srcPoints[ id * 2 + 1 ]
if ( px >= minX && px <= maxX && py >= minY && py <= maxY ) {selection.push(id)
}
}
// for every subsection do select
var offsets = sublevels[ level ]
var off0 = offsets[ from * 4 + 0 ]
var off1 = offsets[ from * 4 + 1 ]
var off2 = offsets[ from * 4 + 2 ]
var off3 = offsets[ from * 4 + 3 ]
var end = nextOffset(offsets, from + 1)
var d2 = d * .5
var nextLevel = level + 1
select( lox, loy, d2, nextLevel, off0, off1 || off2 || off3 || end)
select( lox, loy + d2, d2, nextLevel, off1, off2 || off3 || end)
select( lox + d2, loy, d2, nextLevel, off2, off3 || end)
select( lox + d2, loy + d2, d2, nextLevel, off3, end)
}
function nextOffset(offsets, from) {
var offset = null, i = 0
while(offset === null) {
offset = offsets[ from * 4 + i ]
i++
if (i > offsets.length) { return null }
}
return offset
}
return selection
}
// get range offsets within levels to render lods appropriate for zoom level
// TODO: it is possible to store minSize of a point to optimize neede level calc
function lod (lox, loy, hix, hiy, maxLevel) {
var ranges = []
for (var level = 0; level < maxLevel; level++) {
var levelGroups = groups[level]
var from = offsets[level][0]
var levelGroupStart = group(lox, loy, level)
var levelGroupEnd = group(hix, hiy, level)
// FIXME: utilize sublevels to speed up search range here
var startOffset = search.ge(levelGroups, levelGroupStart)
var endOffset = search.gt(levelGroups, levelGroupEnd, startOffset, levelGroups.length - 1)
ranges[level] = [startOffset + from, endOffset + from]
}
return ranges
}
// get group id closest to the x,y coordinate, corresponding to a level
function group (x, y, level) {
var group = 1
var cx = .5, cy = .5
var diam = .5
for (var i = 0; i < level; i++) {
group <<= 2
group += x < cx ? (y < cy ? 0 : 1) : (y < cy ? 2 : 3)
diam *= .5
cx += x < cx ? -diam : diam
cy += y < cy ? -diam : diam
}
return group
}
}
// normalize points by bounds
function normalize (pts, bounds) {
var lox = bounds[0];
var loy = bounds[1];
var hix = bounds[2];
var hiy = bounds[3];
var scaleX = 1.0 / (hix - lox)
var scaleY = 1.0 / (hiy - loy)
var result = new Array(pts.length)
for (var i = 0, n = pts.length / 2; i < n; i++) {
result[2*i] = clamp((pts[2*i] - lox) * scaleX, 0, 1)
result[2*i+1] = clamp((pts[2*i+1] - loy) * scaleY, 0, 1)
}
return result
}
},{"array-bounds":14,"binary-search-bounds":39,"clamp":58,"defined":87,"dtype":91,"flatten-vertex-data":156,"is-obj":248,"math-log2":252,"parse-rect":265,"pick-by-alias":271}],12:[function(_dereq_,module,exports){
module.exports = absolutize
/**
* redefine `path` with absolute coordinates
*
* @param {Array} path
* @return {Array}
*/
function absolutize(path){
var startX = 0
var startY = 0
var x = 0
var y = 0
return path.map(function(seg){
seg = seg.slice()
var type = seg[0]
var command = type.toUpperCase()
// is relative
if (type != command) {
seg[0] = command
switch (type) {
case 'a':
seg[6] += x
seg[7] += y
break
case 'v':
seg[1] += y
break
case 'h':
seg[1] += x
break
default:
for (var i = 1; i < seg.length;) {
seg[i++] += x
seg[i++] += y
}
}
}
// update cursor state
switch (command) {
case 'Z':
x = startX
y = startY
break
case 'H':
x = seg[1]
break
case 'V':
y = seg[1]
break
case 'M':
x = startX = seg[1]
y = startY = seg[2]
break
default:
x = seg[seg.length - 2]
y = seg[seg.length - 1]
}
return seg
})
}
},{}],13:[function(_dereq_,module,exports){
var padLeft = _dereq_('pad-left')
module.exports = addLineNumbers
function addLineNumbers (string, start, delim) {
start = typeof start === 'number' ? start : 1
delim = delim || ': '
var lines = string.split(/\r?\n/)
var totalDigits = String(lines.length + start - 1).length
return lines.map(function (line, i) {
var c = i + start
var digits = String(c).length
var prefix = padLeft(c, totalDigits - digits)
return prefix + delim + line
}).join('\n')
}
},{"pad-left":263}],14:[function(_dereq_,module,exports){
'use strict'
module.exports = normalize;
function normalize (arr, dim) {
if (!arr || arr.length == null) throw Error('Argument should be an array')
if (dim == null) dim = 1
else dim = Math.floor(dim)
var bounds = Array(dim * 2)
for (var offset = 0; offset < dim; offset++) {
var max = -Infinity, min = Infinity, i = offset, l = arr.length;
for (; i < l; i+=dim) {
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
bounds[offset] = min
bounds[dim + offset] = max
}
return bounds;
}
},{}],15:[function(_dereq_,module,exports){
'use strict'
var getBounds = _dereq_('array-bounds')
module.exports = normalize;
function normalize (arr, dim, bounds) {
if (!arr || arr.length == null) throw Error('Argument should be an array')
if (dim == null) dim = 1
if (bounds == null) bounds = getBounds(arr, dim)
for (var offset = 0; offset < dim; offset++) {
var max = bounds[dim + offset], min = bounds[offset], i = offset, l = arr.length;
if (max === Infinity && min === -Infinity) {
for (i = offset; i < l; i+=dim) {
arr[i] = arr[i] === max ? 1 : arr[i] === min ? 0 : .5
}
}
else if (max === Infinity) {
for (i = offset; i < l; i+=dim) {
arr[i] = arr[i] === max ? 1 : 0
}
}
else if (min === -Infinity) {
for (i = offset; i < l; i+=dim) {
arr[i] = arr[i] === min ? 0 : 1
}
}
else {
var range = max - min
for (i = offset; i < l; i+=dim) {
if (!isNaN(arr[i])) {
arr[i] = range === 0 ? .5 : (arr[i] - min) / range
}
}
}
}
return arr;
}
},{"array-bounds":14}],16:[function(_dereq_,module,exports){
module.exports = function newArray(start, end) {
var n0 = typeof start === 'number',
n1 = typeof end === 'number'
if (n0 && !n1) {
end = start
start = 0
} else if (!n0 && !n1) {
start = 0
end = 0
}
start = start|0
end = end|0
var len = end-start
if (len<0)
throw new Error('array length must be positive')
var a = new Array(len)
for (var i=0, c=start; i<len; i++, c++)
a[i] = c
return a
}
},{}],17:[function(_dereq_,module,exports){
(function (global){(function (){
'use strict';
var objectAssign = _dereq_('object-assign');
// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js
// original notice:
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
function compare(a, b) {
if (a === b) {
return 0;
}
var x = a.length;
var y = b.length;
for (var i = 0, len = Math.min(x, y); i < len; ++i) {
if (a[i] !== b[i]) {
x = a[i];
y = b[i];
break;
}
}
if (x < y) {
return -1;
}
if (y < x) {
return 1;
}
return 0;
}
function isBuffer(b) {
if (global.Buffer && typeof global.Buffer.isBuffer === 'function') {
return global.Buffer.isBuffer(b);
}
return !!(b != null && b._isBuffer);
}
// based on node assert, original notice:
// NB: The URL to the CommonJS spec is kept just for tradition.
// node-assert has evolved a lot since then, both in API and behavior.
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var util = _dereq_('util/');
var hasOwn = Object.prototype.hasOwnProperty;
var pSlice = Array.prototype.slice;
var functionsHaveNames = (function () {
return function foo() {}.name === 'foo';
}());
function pToString (obj) {
return Object.prototype.toString.call(obj);
}
function isView(arrbuf) {
if (isBuffer(arrbuf)) {
return false;
}
if (typeof global.ArrayBuffer !== 'function') {
return false;
}
if (typeof ArrayBuffer.isView === 'function') {
return ArrayBuffer.isView(arrbuf);
}
if (!arrbuf) {
return false;
}
if (arrbuf instanceof DataView) {
return true;
}
if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {
return true;
}
return false;
}
// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
var assert = module.exports = ok;
// 2. The AssertionError is defined in assert.
// new assert.AssertionError({ message: message,
// actual: actual,
// expected: expected })
var regex = /\s*function\s+([^\(\s]*)\s*/;
// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js
function getName(func) {
if (!util.isFunction(func)) {
return;
}
if (functionsHaveNames) {
return func.name;
}
var str = func.toString();
var match = str.match(regex);
return match && match[1];
}
assert.AssertionError = function AssertionError(options) {
this.name = 'AssertionError';
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
if (options.message) {
this.message = options.message;
this.generatedMessage = false;
} else {
this.message = getMessage(this);
this.generatedMessage = true;
}
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
} else {
// non v8 browsers so we can have a stacktrace
var err = new Error();
if (err.stack) {
var out = err.stack;
// try to strip useless frames
var fn_name = getName(stackStartFunction);
var idx = out.indexOf('\n' + fn_name);
if (idx >= 0) {
// once we have located the function frame
// we need to strip out everything before it (and its line)
var next_line = out.indexOf('\n', idx + 1);
out = out.substring(next_line + 1);
}
this.stack = out;
}
}
};
// assert.AssertionError instanceof Error
util.inherits(assert.AssertionError, Error);
function truncate(s, n) {
if (typeof s === 'string') {
return s.length < n ? s : s.slice(0, n);
} else {
return s;
}
}
function inspect(something) {
if (functionsHaveNames || !util.isFunction(something)) {
return util.inspect(something);
}
var rawname = getName(something);
var name = rawname ? ': ' + rawname : '';
return '[Function' + name + ']';
}
function getMessage(self) {
return truncate(inspect(self.actual), 128) + ' ' +
self.operator + ' ' +
truncate(inspect(self.expected), 128);
}
// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.
// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;
// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, !!guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.
function ok(value, message) {
if (!value) fail(value, true, message, '==', assert.ok);
}
assert.ok = ok;
// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);
assert.equal = function equal(actual, expected, message) {
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
};
// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, '!=', assert.notEqual);
}
};
// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!_deepEqual(actual, expected, false)) {
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
}
};
assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {
if (!_deepEqual(actual, expected, true)) {
fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);
}
};
function _deepEqual(actual, expected, strict, memos) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
} else if (isBuffer(actual) && isBuffer(expected)) {
return compare(actual, expected) === 0;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (util.isDate(actual) && util.isDate(expected)) {
return actual.getTime() === expected.getTime();
// 7.3 If the expected value is a RegExp object, the actual value is
// equivalent if it is also a RegExp object with the same source and
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
} else if (util.isRegExp(actual) && util.isRegExp(expected)) {
return actual.source === expected.source &&
actual.global === expected.global &&
actual.multiline === expected.multiline &&
actual.lastIndex === expected.lastIndex &&
actual.ignoreCase === expected.ignoreCase;
// 7.4. Other pairs that do not both pass typeof value == 'object',
// equivalence is determined by ==.
} else if ((actual === null || typeof actual !== 'object') &&
(expected === null || typeof expected !== 'object')) {
return strict ? actual === expected : actual == expected;
// If both values are instances of typed arrays, wrap their underlying
// ArrayBuffers in a Buffer each to increase performance
// This optimization requires the arrays to have the same type as checked by
// Object.prototype.toString (aka pToString). Never perform binary
// comparisons for Float*Arrays, though, since e.g. +0 === -0 but their
// bit patterns are not identical.
} else if (isView(actual) && isView(expected) &&
pToString(actual) === pToString(expected) &&
!(actual instanceof Float32Array ||
actual instanceof Float64Array)) {
return compare(new Uint8Array(actual.buffer),
new Uint8Array(expected.buffer)) === 0;
// 7.5 For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else if (isBuffer(actual) !== isBuffer(expected)) {
return false;
} else {
memos = memos || {actual: [], expected: []};
var actualIndex = memos.actual.indexOf(actual);
if (actualIndex !== -1) {
if (actualIndex === memos.expected.indexOf(expected)) {
return true;
}
}
memos.actual.push(actual);
memos.expected.push(expected);
return objEquiv(actual, expected, strict, memos);
}
}
function isArguments(object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function objEquiv(a, b, strict, actualVisitedObjects) {
if (a === null || a === undefined || b === null || b === undefined)
return false;
// if one is a primitive, the other must be same
if (util.isPrimitive(a) || util.isPrimitive(b))
return a === b;
if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
return false;
var aIsArgs = isArguments(a);
var bIsArgs = isArguments(b);
if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
return false;
if (aIsArgs) {
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b, strict);
}
var ka = objectKeys(a);
var kb = objectKeys(b);
var key, i;
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length !== kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] !== kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))
return false;
}
return true;
}
// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (_deepEqual(actual, expected, false)) {
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
}
};
assert.notDeepStrictEqual = notDeepStrictEqual;
function notDeepStrictEqual(actual, expected, message) {
if (_deepEqual(actual, expected, true)) {
fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
}
}
// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, '===', assert.strictEqual);
}
};
// 10. The strict non-equality assertion tests for strict inequality, as
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
fail(actual, expected, message, '!==', assert.notStrictEqual);
}
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (Object.prototype.toString.call(expected) == '[object RegExp]') {
return expected.test(actual);
}
try {
if (actual instanceof expected) {
return true;
}
} catch (e) {
// Ignore. The instanceof check doesn't work for arrow functions.
}
if (Error.isPrototypeOf(expected)) {
return false;
}
return expected.call({}, actual) === true;
}
function _tryBlock(block) {
var error;
try {
block();
} catch (e) {
error = e;
}
return error;
}
function _throws(shouldThrow, block, expected, message) {
var actual;
if (typeof block !== 'function') {
throw new TypeError('"block" argument must be a function');
}
if (typeof expected === 'string') {
message = expected;
expected = null;
}
actual = _tryBlock(block);
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
(message ? ' ' + message : '.');
if (shouldThrow && !actual) {
fail(actual, expected, 'Missing expected exception' + message);
}
var userProvidedMessage = typeof message === 'string';
var isUnwantedException = !shouldThrow && util.isError(actual);
var isUnexpectedException = !shouldThrow && actual && !expected;
if ((isUnwantedException &&
userProvidedMessage &&
expectedException(actual, expected)) ||
isUnexpectedException) {
fail(actual, expected, 'Got unwanted exception' + message);
}
if ((shouldThrow && actual && expected &&
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
throw actual;
}
}
// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);
assert.throws = function(block, /*optional*/error, /*optional*/message) {
_throws(true, block, error, message);
};
// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
_throws(false, block, error, message);
};
assert.ifError = function(err) { if (err) throw err; };
// Expose a strict only variant of assert
function strict(value, message) {
if (!value) fail(value, true, message, '==', strict);
}
assert.strict = objectAssign(strict, assert, {
equal: assert.strictEqual,
deepEqual: assert.deepStrictEqual,
notEqual: assert.notStrictEqual,
notDeepEqual: assert.notDeepStrictEqual
});
assert.strict.strict = assert.strict;
var objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) {
if (hasOwn.call(obj, key)) keys.push(key);
}
return keys;
};
}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"object-assign":262,"util/":20}],18:[function(_dereq_,module,exports){
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
},{}],19:[function(_dereq_,module,exports){
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
},{}],20:[function(_dereq_,module,exports){
(function (process,global){(function (){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (!isString(f)) {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
// Allow for deprecating things in the process of starting up.
if (isUndefined(global.process)) {
return function() {
return exports.deprecate(fn, msg).apply(this, arguments);
};
}
if (process.noDeprecation === true) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
};
var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
if (isUndefined(debugEnviron))
debugEnviron = process.env.NODE_DEBUG || '';
set = set.toUpperCase();
if (!debugs[set]) {
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
var pid = process.pid;
debugs[set] = function() {
var msg = exports.format.apply(exports, arguments);
console.error('%s %d: %s', set, pid, msg);
};
} else {
debugs[set] = function() {};
}
}
return debugs[set];
};
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][1] + 'm';
} else {
return str;
}
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// IE doesn't make error fields non-enumerable
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
if (isError(value)
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
return formatError(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function(key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value))
return ctx.stylize('' + value, 'number');
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function(key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function(line) {
return ' ' + line