should-format
Advanced tools
Comparing version 2.0.0 to 3.0.0
@@ -5,36 +5,5 @@ 'use strict'; | ||
var getType = _interopDefault(require('should-type')); | ||
var t = _interopDefault(require('should-type')); | ||
var shouldTypeAdaptors = require('should-type-adaptors'); | ||
var EOL = '\n'; | ||
function indent(v, indentation) { | ||
return v | ||
.split(EOL) | ||
.map(function(vv) { | ||
return indentation + vv; | ||
}) | ||
.join(EOL); | ||
} | ||
function pad(str, value, filler) { | ||
str = String(str) | ||
var isRight = false; | ||
if(value < 0) { | ||
isRight = true; | ||
value = -value; | ||
} | ||
if(str.length < value) { | ||
var padding = new Array(value - str.length + 1).join(filler); | ||
return isRight ? str + padding : padding + str; | ||
} else{ | ||
return str; | ||
} | ||
} | ||
function pad0(str, value) { | ||
return pad(str, value, '0'); | ||
} | ||
function looksLikeANumber(n) { | ||
@@ -47,7 +16,7 @@ return !!n.match(/\d+/); | ||
var bNum = looksLikeANumber(b); | ||
if(aNum && bNum) { | ||
if (aNum && bNum) { | ||
return 1*a - 1*b; | ||
} else if(aNum && !bNum) { | ||
} else if (aNum && !bNum) { | ||
return -1; | ||
} else if(!aNum && bNum) { | ||
} else if (!aNum && bNum) { | ||
return 1; | ||
@@ -67,9 +36,2 @@ } else { | ||
var INDENT = ' '; | ||
function addSpaces(str) { | ||
return indent(str, INDENT); | ||
} | ||
function Formatter(opts) { | ||
@@ -79,6 +41,7 @@ opts = opts || {}; | ||
this.seen = []; | ||
var keysFunc; | ||
if(typeof opts.keysFunc === 'function') { | ||
if (typeof opts.keysFunc === 'function') { | ||
keysFunc = opts.keysFunc; | ||
} else if(opts.keys === false) { | ||
} else if (opts.keys === false) { | ||
keysFunc = Object.getOwnPropertyNames; | ||
@@ -89,3 +52,3 @@ } else { | ||
this.keys = genKeysFunc(keysFunc); | ||
this.getKeys = genKeysFunc(keysFunc); | ||
@@ -98,2 +61,4 @@ this.maxLineLength = typeof opts.maxLineLength === 'number' ? opts.maxLineLength : 60; | ||
Formatter.prototype = { | ||
@@ -103,114 +68,75 @@ constructor: Formatter, | ||
format: function(value) { | ||
var t = getType(value); | ||
var name1 = t.type, name2 = t.type; | ||
if(t.cls) { | ||
name1 += '_' + t.cls; | ||
name2 += '_' + t.cls; | ||
} | ||
if(t.sub) { | ||
name2 += '_' + t.sub; | ||
} | ||
var f = this['_format_' + name2] || this['_format_' + name1] || this['_format_' + t.type] || this.defaultFormat; | ||
return f.call(this, value).trim(); | ||
}, | ||
var tp = t(value); | ||
_formatObject: function(value, opts) { | ||
opts = opts || {}; | ||
var mainKeys = opts.keys || this.keys(value); | ||
var len = 0; | ||
var formatPropertyValue = opts.formatPropertyValue || this.formatPropertyValue; | ||
var formatPropertyName = opts.formatPropertyName || this.formatPropertyName; | ||
var keyValueSep = opts.keyValueSep || ': '; | ||
var keyFilter = opts.keyFilter || function() { return true; }; | ||
this.seen.push(value); | ||
var keys = []; | ||
mainKeys.forEach(function(key) { | ||
if(!keyFilter(key)) return; | ||
var fName = formatPropertyName.call(this, key); | ||
var f = (fName ? fName + keyValueSep : '') + formatPropertyValue.call(this, value, key); | ||
len += f.length; | ||
keys.push(f); | ||
}, this); | ||
this.seen.pop(); | ||
(opts.additionalProperties || []).forEach(function(keyValue) { | ||
var f = keyValue[0] + keyValueSep + this.format(keyValue[1]); | ||
len += f.length; | ||
keys.push(f); | ||
}, this); | ||
var prefix = opts.prefix || Formatter.constructorName(value) || ''; | ||
if(prefix.length > 0) prefix += ' '; | ||
var lbracket, rbracket; | ||
if(Array.isArray(opts.brackets)) { | ||
lbracket = opts.brackets && opts.brackets[0]; | ||
rbracket = opts.brackets && opts.brackets[1]; | ||
} else { | ||
lbracket = '{'; | ||
rbracket = '}'; | ||
if (tp.type === t.OBJECT && this.alreadySeen(value)) { | ||
return '[Circular]'; | ||
} | ||
var rootValue = opts.value || ''; | ||
if(keys.length === 0) | ||
return rootValue || (prefix + lbracket + rbracket); | ||
if(len <= this.maxLineLength) { | ||
return prefix + lbracket + ' ' + (rootValue ? rootValue + ' ' : '') + keys.join(this.propSep + ' ') + ' ' + rbracket; | ||
} else { | ||
return prefix + lbracket + '\n' + (rootValue ? ' ' + rootValue + '\n' : '') + keys.map(addSpaces).join(this.propSep + '\n') + '\n' + rbracket; | ||
var tries = tp.toTryTypes(); | ||
var f = this.defaultFormat; | ||
while (tries.length) { | ||
var toTry = tries.shift(); | ||
var name = Formatter.formatterFunctionName(toTry); | ||
if (this[name]) { | ||
f = this[name]; | ||
break; | ||
} | ||
} | ||
return f.call(this, value).trim(); | ||
}, | ||
formatPropertyName: function(name) { | ||
return name.match(/^[a-zA-Z_$][a-zA-Z_$0-9]*$/) ? name : this.format(name); | ||
defaultFormat: function(obj) { | ||
return String(obj); | ||
}, | ||
formatProperty: function(value, prop) { | ||
var desc = Formatter.getPropertyDescriptor(value, prop); | ||
alreadySeen: function(value) { | ||
return this.seen.indexOf(value) >= 0; | ||
} | ||
var propName = this.formatPropertyName(prop); | ||
}; | ||
var propValue = desc.get && desc.set ? | ||
'[Getter/Setter]' : desc.get ? | ||
'[Getter]' : desc.set ? | ||
'[Setter]' : this.seen.indexOf(desc.value) >= 0 ? | ||
'[Circular]' : | ||
this.format(desc.value); | ||
Formatter.addType = function addType(tp, f) { | ||
Formatter.prototype[Formatter.formatterFunctionName(tp)] = f; | ||
}; | ||
return propName + ': ' + propValue; | ||
}, | ||
Formatter.formatterFunctionName = function formatterFunctionName(tp) { | ||
return '_format_' + tp.toString('_'); | ||
}; | ||
formatPropertyValue: function(value, prop) { | ||
var desc = Formatter.getPropertyDescriptor(value, prop); | ||
var EOL = '\n'; | ||
var propValue = desc.get && desc.set ? | ||
'[Getter/Setter]' : desc.get ? | ||
'[Getter]' : desc.set ? | ||
'[Setter]' : this.seen.indexOf(desc.value) >= 0 ? | ||
'[Circular]' : | ||
this.format(desc.value); | ||
function indent(v, indentation) { | ||
return v | ||
.split(EOL) | ||
.map(function(vv) { | ||
return indentation + vv; | ||
}) | ||
.join(EOL); | ||
} | ||
return propValue; | ||
function pad(str, value, filler) { | ||
str = String(str); | ||
var isRight = false; | ||
if (value < 0) { | ||
isRight = true; | ||
value = -value; | ||
} | ||
}; | ||
Formatter.add = function add(type, cls, sub, f) { | ||
var args = Array.prototype.slice.call(arguments); | ||
f = args.pop(); | ||
Formatter.prototype['_format_' + args.join('_')] = f; | ||
}; | ||
if (str.length < value) { | ||
var padding = new Array(value - str.length + 1).join(filler); | ||
return isRight ? str + padding : padding + str; | ||
} else { | ||
return str; | ||
} | ||
} | ||
function pad0(str, value) { | ||
return pad(str, value, '0'); | ||
} | ||
var functionNameRE = /^\s*function\s*(\S*)\s*\(/; | ||
Formatter.functionName = function functionName(f) { | ||
if(f.name) { | ||
function functionName(f) { | ||
if (f.name) { | ||
return f.name; | ||
@@ -225,14 +151,12 @@ } | ||
return name; | ||
}; | ||
} | ||
Formatter.constructorName = function(obj) { | ||
function constructorName(obj) { | ||
while (obj) { | ||
var descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor'); | ||
if (descriptor !== undefined && | ||
typeof descriptor.value === 'function') { | ||
var name = Formatter.functionName(descriptor.value); | ||
if(name !== '') { | ||
return name; | ||
} | ||
if (descriptor !== undefined && typeof descriptor.value === 'function') { | ||
var name = functionName(descriptor.value); | ||
if (name !== '') { | ||
return name; | ||
} | ||
} | ||
@@ -242,92 +166,153 @@ | ||
} | ||
}; | ||
} | ||
Formatter.getPropertyDescriptor = function(obj, value) { | ||
var INDENT = ' '; | ||
function addSpaces(str) { | ||
return indent(str, INDENT); | ||
} | ||
function typeAdaptorForEachFormat(obj, opts) { | ||
opts = opts || {}; | ||
var filterKey = opts.filterKey || function() { return true; }; | ||
var formatKey = opts.formatKey || this.format; | ||
var formatValue = opts.formatValue || this.format; | ||
var keyValueSep = typeof opts.keyValueSep !== 'undefined' ? opts.keyValueSep : ': '; | ||
this.seen.push(obj); | ||
var formatLength = 0; | ||
var pairs = []; | ||
shouldTypeAdaptors.forEach(obj, function(value, key) { | ||
if (!filterKey(key)) { | ||
return; | ||
} | ||
var formattedKey = formatKey.call(this, key); | ||
var formattedValue = formatValue.call(this, value, key); | ||
var pair = formattedKey ? (formattedKey + keyValueSep + formattedValue) : formattedValue; | ||
formatLength += pair.length; | ||
pairs.push(pair); | ||
}, this); | ||
this.seen.pop(); | ||
(opts.additionalKeys || []).forEach(function(keyValue) { | ||
var pair = keyValue[0] + keyValueSep + this.format(keyValue[1]); | ||
formatLength += pair.length; | ||
pairs.push(pair); | ||
}, this); | ||
var prefix = opts.prefix || constructorName(obj) || ''; | ||
if (prefix.length > 0) { | ||
prefix += ' '; | ||
} | ||
var lbracket, rbracket; | ||
if (Array.isArray(opts.brackets)) { | ||
lbracket = opts.brackets[0]; | ||
rbracket = opts.brackets[1]; | ||
} else { | ||
lbracket = '{'; | ||
rbracket = '}'; | ||
} | ||
var rootValue = opts.value || ''; | ||
if (pairs.length === 0) { | ||
return rootValue || (prefix + lbracket + rbracket); | ||
} | ||
if (formatLength <= this.maxLineLength) { | ||
return prefix + lbracket + ' ' + (rootValue ? rootValue + ' ' : '') + pairs.join(this.propSep + ' ') + ' ' + rbracket; | ||
} else { | ||
return prefix + lbracket + '\n' + (rootValue ? ' ' + rootValue + '\n' : '') + pairs.map(addSpaces).join(this.propSep + '\n') + '\n' + rbracket; | ||
} | ||
} | ||
function formatPlainObjectKey(key) { | ||
return typeof key === 'string' && key.match(/^[a-zA-Z_$][a-zA-Z_$0-9]*$/) ? key : this.format(key); | ||
} | ||
function getPropertyDescriptor(obj, key) { | ||
var desc; | ||
try { | ||
desc = Object.getOwnPropertyDescriptor(obj, value) || {value: obj[value]}; | ||
} catch(e) { | ||
desc = {value: e}; | ||
desc = Object.getOwnPropertyDescriptor(obj, key) || { value: obj[key] }; | ||
} catch (e) { | ||
desc = { value: e }; | ||
} | ||
return desc; | ||
}; | ||
} | ||
Formatter.generateFunctionForIndexedArray = function generateFunctionForIndexedArray(lengthProp, name, padding) { | ||
return function(value) { | ||
var max = this.byteArrayMaxLength || 50; | ||
var length = value[lengthProp]; | ||
var formattedValues = []; | ||
var len = 0; | ||
for(var i = 0; i < max && i < length; i++) { | ||
var b = value[i] || 0; | ||
var v = pad0(b.toString(16), padding); | ||
len += v.length; | ||
formattedValues.push(v); | ||
} | ||
var prefix = value.constructor.name || name || ''; | ||
if(prefix) prefix += ' '; | ||
function formatPlainObjectValue(obj, key) { | ||
var desc = getPropertyDescriptor(obj, key); | ||
if (desc.get && desc.set) { | ||
return '[Getter/Setter]'; | ||
} | ||
if (desc.get) { | ||
return '[Getter]'; | ||
} | ||
if (desc.set) { | ||
return '[Setter]'; | ||
} | ||
if(formattedValues.length === 0) | ||
return prefix + '[]'; | ||
return this.format(desc.value); | ||
} | ||
if(len <= this.maxLineLength) { | ||
return prefix + '[ ' + formattedValues.join(this.propSep + ' ') + ' ' + ']'; | ||
} else { | ||
return prefix + '[\n' + formattedValues.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; | ||
} | ||
function formatPlainObject(obj, opts) { | ||
opts = opts || {}; | ||
opts.keyValueSep = ': '; | ||
opts.formatKey = opts.formatKey || formatPlainObjectKey; | ||
opts.formatValue = opts.formatValue || function(value, key) { | ||
return formatPlainObjectValue.call(this, obj, key); | ||
}; | ||
}; | ||
return typeAdaptorForEachFormat.call(this, obj, opts); | ||
} | ||
Formatter.add('undefined', function() { return 'undefined' }); | ||
Formatter.add('null', function() { return 'null' }); | ||
Formatter.add('boolean', function(value) { return value ? 'true': 'false' }); | ||
Formatter.add('symbol', function(value) { return value.toString() }); | ||
['number', 'boolean'].forEach(function(name) { | ||
Formatter.add('object', name, function(value) { | ||
return this._formatObject(value, { | ||
additionalProperties: [['[[PrimitiveValue]]', value.valueOf()]] | ||
}); | ||
function formatWrapper1(value) { | ||
return formatPlainObject.call(this, value, { | ||
additionalKeys: [['[[PrimitiveValue]]', value.valueOf()]] | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'string', function(value) { | ||
function formatWrapper2(value) { | ||
var realValue = value.valueOf(); | ||
return this._formatObject(value, { | ||
keyFilter: function(key) { | ||
return formatPlainObject.call(this, value, { | ||
filterKey: function(key) { | ||
//skip useless indexed properties | ||
return !(key.match(/\d+/) && parseInt(key, 10) < realValue.length); | ||
}, | ||
additionalProperties: [['[[PrimitiveValue]]', realValue]] | ||
additionalKeys: [['[[PrimitiveValue]]', realValue]] | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'regexp', function(value) { | ||
return this._formatObject(value, { | ||
function formatRegExp(value) { | ||
return formatPlainObject.call(this, value, { | ||
value: String(value) | ||
}); | ||
}); | ||
} | ||
Formatter.add('number', function(value) { | ||
if(value === 0 && 1 / value < 0) return '-0'; | ||
return String(value); | ||
}); | ||
function formatFunction(value) { | ||
var obj = {}; | ||
Object.keys(value).forEach(function(key) { | ||
obj[key] = value[key]; | ||
}); | ||
return formatPlainObject.call(this, obj, { | ||
prefix: 'Function', | ||
additionalKeys: [['name', functionName(value)]] | ||
}); | ||
} | ||
Formatter.add('string', function(value) { | ||
return '\'' + JSON.stringify(value).replace(/^"|"$/g, '') | ||
.replace(/'/g, "\\'") | ||
.replace(/\\"/g, '"') + '\''; | ||
}); | ||
Formatter.add('object', function(value) { | ||
return this._formatObject(value); | ||
}); | ||
Formatter.add('object', 'arguments', function(value) { | ||
return this._formatObject(value, { | ||
prefix: 'Arguments', | ||
formatPropertyName: function(key) { | ||
if(!key.match(/\d+/)) { | ||
return this.formatPropertyName(key); | ||
function formatArray(value) { | ||
return formatPlainObject.call(this, value, { | ||
formatKey: function(key) { | ||
if (!key.match(/\d+/)) { | ||
return formatPlainObjectKey.call(this, key); | ||
} | ||
@@ -337,17 +322,17 @@ }, | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'array', function(value) { | ||
return this._formatObject(value, { | ||
formatPropertyName: function(key) { | ||
if(!key.match(/\d+/)) { | ||
return this.formatPropertyName(key); | ||
function formatArguments(value) { | ||
return formatPlainObject.call(this, value, { | ||
formatKey: function(key) { | ||
if (!key.match(/\d+/)) { | ||
return formatPlainObjectKey.call(this, key); | ||
} | ||
}, | ||
brackets: ['[', ']'] | ||
brackets: ['[', ']'], | ||
prefix: 'Arguments' | ||
}); | ||
}); | ||
} | ||
function formatDate(value, isUTC) { | ||
function _formatDate(value, isUTC) { | ||
var prefix = isUTC ? 'UTC' : ''; | ||
@@ -378,167 +363,183 @@ | ||
Formatter.add('object', 'date', function(value) { | ||
return this._formatObject(value, { value: formatDate(value, this.isUTCdate) }); | ||
}); | ||
function formatDate(value) { | ||
return formatPlainObject.call(this, value, { value: _formatDate(value, this.isUTCdate) }); | ||
} | ||
Formatter.add('function', function(value) { | ||
return this._formatObject(value, { | ||
additionalProperties: [['name', Formatter.functionName(value)]] | ||
function formatError(value) { | ||
return formatPlainObject.call(this, value, { | ||
prefix: value.name, | ||
additionalKeys: [['message', value.message]] | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'error', function(value) { | ||
return this._formatObject(value, { | ||
prefix: value.name, | ||
additionalProperties: [['message', value.message]] | ||
function generateFormatForNumberArray(lengthProp, name, padding) { | ||
return function(value) { | ||
var max = this.byteArrayMaxLength || 50; | ||
var length = value[lengthProp]; | ||
var formattedValues = []; | ||
var len = 0; | ||
for (var i = 0; i < max && i < length; i++) { | ||
var b = value[i] || 0; | ||
var v = pad0(b.toString(16), padding); | ||
len += v.length; | ||
formattedValues.push(v); | ||
} | ||
var prefix = value.constructor.name || name || ''; | ||
if (prefix) { | ||
prefix += ' '; | ||
} | ||
if (formattedValues.length === 0) { | ||
return prefix + '[]'; | ||
} | ||
if (len <= this.maxLineLength) { | ||
return prefix + '[ ' + formattedValues.join(this.propSep + ' ') + ' ' + ']'; | ||
} else { | ||
return prefix + '[\n' + formattedValues.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; | ||
} | ||
}; | ||
} | ||
function formatMap(obj) { | ||
return typeAdaptorForEachFormat.call(this, obj, { | ||
keyValueSep: ' => ' | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'buffer', Formatter.generateFunctionForIndexedArray('length', 'Buffer', 2)); | ||
function formatSet(obj) { | ||
return typeAdaptorForEachFormat.call(this, obj, { | ||
keyValueSep: '', | ||
formatKey: function() { return ''; } | ||
}); | ||
} | ||
Formatter.add('object', 'array-buffer', Formatter.generateFunctionForIndexedArray('byteLength', 'ArrayBuffer', 2)); | ||
function genSimdVectorFormat(constructorName, length) { | ||
return function(value) { | ||
var Constructor = value.constructor; | ||
var extractLane = Constructor.extractLane; | ||
Formatter.add('object', 'typed-array', 'int8', Formatter.generateFunctionForIndexedArray('length', 'Int8Array', 2)); | ||
Formatter.add('object', 'typed-array', 'uint8', Formatter.generateFunctionForIndexedArray('length', 'Uint8Array', 2)); | ||
Formatter.add('object', 'typed-array', 'uint8clamped', Formatter.generateFunctionForIndexedArray('length', 'Uint8ClampedArray', 2)); | ||
var len = 0; | ||
var props = []; | ||
Formatter.add('object', 'typed-array', 'int16', Formatter.generateFunctionForIndexedArray('length', 'Int16Array', 4)); | ||
Formatter.add('object', 'typed-array', 'uint16', Formatter.generateFunctionForIndexedArray('length', 'Uint16Array', 4)); | ||
for (var i = 0; i < length; i ++) { | ||
var key = this.format(extractLane(value, i)); | ||
len += key.length; | ||
props.push(key); | ||
} | ||
Formatter.add('object', 'typed-array', 'int32', Formatter.generateFunctionForIndexedArray('length', 'Int32Array', 8)); | ||
Formatter.add('object', 'typed-array', 'uint32', Formatter.generateFunctionForIndexedArray('length', 'Uint32Array', 8)); | ||
if (len <= this.maxLineLength) { | ||
return constructorName + ' [ ' + props.join(this.propSep + ' ') + ' ]'; | ||
} else { | ||
return constructorName + ' [\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; | ||
} | ||
}; | ||
} | ||
//TODO add float32 and float64 | ||
function defaultFormat(value, opts) { | ||
return new Formatter(opts).format(value); | ||
} | ||
Formatter.add('object', 'promise', function() { | ||
return '[Promise]';//TODO it could be nice to inspect its state and value | ||
defaultFormat.Formatter = Formatter; | ||
defaultFormat.addSpaces = addSpaces; | ||
defaultFormat.pad0 = pad0; | ||
defaultFormat.functionName = functionName; | ||
defaultFormat.constructorName = constructorName; | ||
defaultFormat.formatPlainObjectKey = formatPlainObjectKey; | ||
// adding primitive types | ||
Formatter.addType(new t.Type(t.UNDEFINED), function() { | ||
return 'undefined'; | ||
}); | ||
Formatter.add('object', 'xhr', function() { | ||
return '[XMLHttpRequest]';//TODO it could be nice to inspect its state | ||
Formatter.addType(new t.Type(t.NULL), function() { | ||
return 'null'; | ||
}); | ||
Formatter.add('object', 'html-element', function(value) { | ||
return value.outerHTML; | ||
Formatter.addType(new t.Type(t.BOOLEAN), function(value) { | ||
return value ? 'true': 'false'; | ||
}); | ||
Formatter.add('object', 'html-element', '#text', function(value) { | ||
return value.nodeValue; | ||
Formatter.addType(new t.Type(t.SYMBOL), function(value) { | ||
return value.toString(); | ||
}); | ||
Formatter.add('object', 'html-element', '#document', function(value) { | ||
return value.documentElement.outerHTML; | ||
Formatter.addType(new t.Type(t.NUMBER), function(value) { | ||
if (value === 0 && 1 / value < 0) { | ||
return '-0'; | ||
} | ||
return String(value); | ||
}); | ||
Formatter.add('object', 'host', function() { | ||
return '[Host]'; | ||
Formatter.addType(new t.Type(t.STRING), function(value) { | ||
return '\'' + JSON.stringify(value).replace(/^"|"$/g, '') | ||
.replace(/'/g, "\\'") | ||
.replace(/\\"/g, '"') + '\''; | ||
}); | ||
Formatter.add('object', 'set', function(value) { | ||
var iter = value.values(); | ||
var len = 0; | ||
Formatter.addType(new t.Type(t.FUNCTION), formatFunction); | ||
this.seen.push(value); | ||
// plain object | ||
Formatter.addType(new t.Type(t.OBJECT), formatPlainObject); | ||
var props = []; | ||
// type wrappers | ||
Formatter.addType(new t.Type(t.OBJECT, t.NUMBER), formatWrapper1); | ||
Formatter.addType(new t.Type(t.OBJECT, t.BOOLEAN), formatWrapper1); | ||
Formatter.addType(new t.Type(t.OBJECT, t.STRING), formatWrapper2); | ||
var next = iter.next(); | ||
while(!next.done) { | ||
var val = next.value; | ||
var f = this.format(val); | ||
len += f.length; | ||
props.push(f); | ||
Formatter.addType(new t.Type(t.OBJECT, t.REGEXP), formatRegExp); | ||
Formatter.addType(new t.Type(t.OBJECT, t.ARRAY), formatArray); | ||
Formatter.addType(new t.Type(t.OBJECT, t.ARGUMENTS), formatArguments); | ||
Formatter.addType(new t.Type(t.OBJECT, t.DATE), formatDate); | ||
Formatter.addType(new t.Type(t.OBJECT, t.ERROR), formatError); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SET), formatSet); | ||
Formatter.addType(new t.Type(t.OBJECT, t.MAP), formatMap); | ||
Formatter.addType(new t.Type(t.OBJECT, t.WEAK_MAP), formatMap); | ||
Formatter.addType(new t.Type(t.OBJECT, t.WEAK_SET), formatSet); | ||
next = iter.next(); | ||
} | ||
Formatter.addType(new t.Type(t.OBJECT, t.BUFFER), generateFormatForNumberArray('length', 'Buffer', 2)); | ||
this.seen.pop(); | ||
Formatter.addType(new t.Type(t.OBJECT, t.ARRAY_BUFFER), generateFormatForNumberArray('byteLength', 'ArrayBuffer', 2)); | ||
if(props.length === 0) return 'Set {}'; | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'int8'), generateFormatForNumberArray('length', 'Int8Array', 2)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'uint8'), generateFormatForNumberArray('length', 'Uint8Array', 2)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'uint8clamped'), generateFormatForNumberArray('length', 'Uint8ClampedArray', 2)); | ||
if(len <= this.maxLineLength) { | ||
return 'Set { ' + props.join(this.propSep + ' ') + ' }'; | ||
} else { | ||
return 'Set {\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + '}'; | ||
} | ||
}); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'int16'), generateFormatForNumberArray('length', 'Int16Array', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'uint16'), generateFormatForNumberArray('length', 'Uint16Array', 4)); | ||
Formatter.add('object', 'map', function(value) { | ||
var iter = value.entries(); | ||
var len = 0; | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'int32'), generateFormatForNumberArray('length', 'Int32Array', 8)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'uint32'), generateFormatForNumberArray('length', 'Uint32Array', 8)); | ||
this.seen.push(value); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'bool16x8'), genSimdVectorFormat('Bool16x8', 8)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'bool32x4'), genSimdVectorFormat('Bool32x4', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'bool8x16'), genSimdVectorFormat('Bool8x16', 16)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'float32x4'), genSimdVectorFormat('Float32x4', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'int16x8'), genSimdVectorFormat('Int16x8', 8)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'int32x4'), genSimdVectorFormat('Int32x4', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'int8x16'), genSimdVectorFormat('Int8x16', 16)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'uint16x8'), genSimdVectorFormat('Uint16x8', 8)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'uint32x4'), genSimdVectorFormat('Uint32x4', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'uint8x16'), genSimdVectorFormat('Uint8x16', 16)); | ||
var props = []; | ||
var next = iter.next(); | ||
while(!next.done) { | ||
var val = next.value; | ||
var fK = this.format(val[0]); | ||
var fV = this.format(val[1]); | ||
Formatter.addType(new t.Type(t.OBJECT, t.PROMISE), function() { | ||
return '[Promise]';//TODO it could be nice to inspect its state and value | ||
}); | ||
var f; | ||
if((fK.length + fV.length + 4) <= this.maxLineLength) { | ||
f = fK + ' => ' + fV; | ||
} else { | ||
f = fK + ' =>\n' + fV; | ||
} | ||
Formatter.addType(new t.Type(t.OBJECT, t.XHR), function() { | ||
return '[XMLHttpRequest]';//TODO it could be nice to inspect its state | ||
}); | ||
len += fK.length + fV.length + 4; | ||
props.push(f); | ||
Formatter.addType(new t.Type(t.OBJECT, t.HTML_ELEMENT), function(value) { | ||
return value.outerHTML; | ||
}); | ||
next = iter.next(); | ||
} | ||
Formatter.addType(new t.Type(t.OBJECT, t.HTML_ELEMENT, '#text'), function(value) { | ||
return value.nodeValue; | ||
}); | ||
this.seen.pop(); | ||
Formatter.addType(new t.Type(t.OBJECT, t.HTML_ELEMENT, '#document'), function(value) { | ||
return value.documentElement.outerHTML; | ||
}); | ||
if(props.length === 0) return 'Map {}'; | ||
if(len <= this.maxLineLength) { | ||
return 'Map { ' + props.join(this.propSep + ' ') + ' }'; | ||
} else { | ||
return 'Map {\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + '}'; | ||
} | ||
Formatter.addType(new t.Type(t.OBJECT, t.HOST), function() { | ||
return '[Host]'; | ||
}); | ||
function simdVectorFormat(constructorName, length) { | ||
return function(value) { | ||
var Constructor = value.constructor; | ||
var extractLane = Constructor.extractLane; | ||
var len = 0; | ||
var props = []; | ||
for(var i = 0; i < length; i ++) { | ||
var key = this.format(extractLane(value, i)); | ||
len += key.length; | ||
props.push(key); | ||
} | ||
if(len <= this.maxLineLength) { | ||
return constructorName + ' [ ' + props.join(this.propSep + ' ') + ' ]'; | ||
} else { | ||
return constructorName + ' [\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; | ||
} | ||
} | ||
} | ||
Formatter.add('object', 'simd', 'bool16x8', simdVectorFormat('Bool16x8', 8)); | ||
Formatter.add('object', 'simd', 'bool32x4', simdVectorFormat('Bool32x4', 4)); | ||
Formatter.add('object', 'simd', 'bool8x16', simdVectorFormat('Bool8x16', 16)); | ||
Formatter.add('object', 'simd', 'float32x4', simdVectorFormat('Float32x4', 4)); | ||
Formatter.add('object', 'simd', 'int16x8', simdVectorFormat('Int16x8', 8)); | ||
Formatter.add('object', 'simd', 'int32x4', simdVectorFormat('Int32x4', 4)); | ||
Formatter.add('object', 'simd', 'int8x16', simdVectorFormat('Int8x16', 16)); | ||
Formatter.add('object', 'simd', 'uint16x8', simdVectorFormat('Uint16x8', 8)); | ||
Formatter.add('object', 'simd', 'uint32x4', simdVectorFormat('Uint32x4', 4)); | ||
Formatter.add('object', 'simd', 'uint8x16', simdVectorFormat('Uint8x16', 16)); | ||
Formatter.prototype.defaultFormat = Formatter.prototype._format_object; | ||
function defaultFormat(value, opts) { | ||
return new Formatter(opts).format(value); | ||
} | ||
defaultFormat.Formatter = Formatter; | ||
module.exports = defaultFormat; |
@@ -1,35 +0,4 @@ | ||
import getType from 'should-type'; | ||
import t from 'should-type'; | ||
import { forEach } from 'should-type-adaptors'; | ||
var EOL = '\n'; | ||
function indent(v, indentation) { | ||
return v | ||
.split(EOL) | ||
.map(function(vv) { | ||
return indentation + vv; | ||
}) | ||
.join(EOL); | ||
} | ||
function pad(str, value, filler) { | ||
str = String(str) | ||
var isRight = false; | ||
if(value < 0) { | ||
isRight = true; | ||
value = -value; | ||
} | ||
if(str.length < value) { | ||
var padding = new Array(value - str.length + 1).join(filler); | ||
return isRight ? str + padding : padding + str; | ||
} else{ | ||
return str; | ||
} | ||
} | ||
function pad0(str, value) { | ||
return pad(str, value, '0'); | ||
} | ||
function looksLikeANumber(n) { | ||
@@ -42,7 +11,7 @@ return !!n.match(/\d+/); | ||
var bNum = looksLikeANumber(b); | ||
if(aNum && bNum) { | ||
if (aNum && bNum) { | ||
return 1*a - 1*b; | ||
} else if(aNum && !bNum) { | ||
} else if (aNum && !bNum) { | ||
return -1; | ||
} else if(!aNum && bNum) { | ||
} else if (!aNum && bNum) { | ||
return 1; | ||
@@ -62,9 +31,2 @@ } else { | ||
var INDENT = ' '; | ||
function addSpaces(str) { | ||
return indent(str, INDENT); | ||
} | ||
function Formatter(opts) { | ||
@@ -74,6 +36,7 @@ opts = opts || {}; | ||
this.seen = []; | ||
var keysFunc; | ||
if(typeof opts.keysFunc === 'function') { | ||
if (typeof opts.keysFunc === 'function') { | ||
keysFunc = opts.keysFunc; | ||
} else if(opts.keys === false) { | ||
} else if (opts.keys === false) { | ||
keysFunc = Object.getOwnPropertyNames; | ||
@@ -84,3 +47,3 @@ } else { | ||
this.keys = genKeysFunc(keysFunc); | ||
this.getKeys = genKeysFunc(keysFunc); | ||
@@ -93,2 +56,4 @@ this.maxLineLength = typeof opts.maxLineLength === 'number' ? opts.maxLineLength : 60; | ||
Formatter.prototype = { | ||
@@ -98,114 +63,75 @@ constructor: Formatter, | ||
format: function(value) { | ||
var t = getType(value); | ||
var name1 = t.type, name2 = t.type; | ||
if(t.cls) { | ||
name1 += '_' + t.cls; | ||
name2 += '_' + t.cls; | ||
} | ||
if(t.sub) { | ||
name2 += '_' + t.sub; | ||
} | ||
var f = this['_format_' + name2] || this['_format_' + name1] || this['_format_' + t.type] || this.defaultFormat; | ||
return f.call(this, value).trim(); | ||
}, | ||
var tp = t(value); | ||
_formatObject: function(value, opts) { | ||
opts = opts || {}; | ||
var mainKeys = opts.keys || this.keys(value); | ||
var len = 0; | ||
var formatPropertyValue = opts.formatPropertyValue || this.formatPropertyValue; | ||
var formatPropertyName = opts.formatPropertyName || this.formatPropertyName; | ||
var keyValueSep = opts.keyValueSep || ': '; | ||
var keyFilter = opts.keyFilter || function() { return true; }; | ||
this.seen.push(value); | ||
var keys = []; | ||
mainKeys.forEach(function(key) { | ||
if(!keyFilter(key)) return; | ||
var fName = formatPropertyName.call(this, key); | ||
var f = (fName ? fName + keyValueSep : '') + formatPropertyValue.call(this, value, key); | ||
len += f.length; | ||
keys.push(f); | ||
}, this); | ||
this.seen.pop(); | ||
(opts.additionalProperties || []).forEach(function(keyValue) { | ||
var f = keyValue[0] + keyValueSep + this.format(keyValue[1]); | ||
len += f.length; | ||
keys.push(f); | ||
}, this); | ||
var prefix = opts.prefix || Formatter.constructorName(value) || ''; | ||
if(prefix.length > 0) prefix += ' '; | ||
var lbracket, rbracket; | ||
if(Array.isArray(opts.brackets)) { | ||
lbracket = opts.brackets && opts.brackets[0]; | ||
rbracket = opts.brackets && opts.brackets[1]; | ||
} else { | ||
lbracket = '{'; | ||
rbracket = '}'; | ||
if (tp.type === t.OBJECT && this.alreadySeen(value)) { | ||
return '[Circular]'; | ||
} | ||
var rootValue = opts.value || ''; | ||
if(keys.length === 0) | ||
return rootValue || (prefix + lbracket + rbracket); | ||
if(len <= this.maxLineLength) { | ||
return prefix + lbracket + ' ' + (rootValue ? rootValue + ' ' : '') + keys.join(this.propSep + ' ') + ' ' + rbracket; | ||
} else { | ||
return prefix + lbracket + '\n' + (rootValue ? ' ' + rootValue + '\n' : '') + keys.map(addSpaces).join(this.propSep + '\n') + '\n' + rbracket; | ||
var tries = tp.toTryTypes(); | ||
var f = this.defaultFormat; | ||
while (tries.length) { | ||
var toTry = tries.shift(); | ||
var name = Formatter.formatterFunctionName(toTry); | ||
if (this[name]) { | ||
f = this[name]; | ||
break; | ||
} | ||
} | ||
return f.call(this, value).trim(); | ||
}, | ||
formatPropertyName: function(name) { | ||
return name.match(/^[a-zA-Z_$][a-zA-Z_$0-9]*$/) ? name : this.format(name); | ||
defaultFormat: function(obj) { | ||
return String(obj); | ||
}, | ||
formatProperty: function(value, prop) { | ||
var desc = Formatter.getPropertyDescriptor(value, prop); | ||
alreadySeen: function(value) { | ||
return this.seen.indexOf(value) >= 0; | ||
} | ||
var propName = this.formatPropertyName(prop); | ||
}; | ||
var propValue = desc.get && desc.set ? | ||
'[Getter/Setter]' : desc.get ? | ||
'[Getter]' : desc.set ? | ||
'[Setter]' : this.seen.indexOf(desc.value) >= 0 ? | ||
'[Circular]' : | ||
this.format(desc.value); | ||
Formatter.addType = function addType(tp, f) { | ||
Formatter.prototype[Formatter.formatterFunctionName(tp)] = f; | ||
}; | ||
return propName + ': ' + propValue; | ||
}, | ||
Formatter.formatterFunctionName = function formatterFunctionName(tp) { | ||
return '_format_' + tp.toString('_'); | ||
}; | ||
formatPropertyValue: function(value, prop) { | ||
var desc = Formatter.getPropertyDescriptor(value, prop); | ||
var EOL = '\n'; | ||
var propValue = desc.get && desc.set ? | ||
'[Getter/Setter]' : desc.get ? | ||
'[Getter]' : desc.set ? | ||
'[Setter]' : this.seen.indexOf(desc.value) >= 0 ? | ||
'[Circular]' : | ||
this.format(desc.value); | ||
function indent(v, indentation) { | ||
return v | ||
.split(EOL) | ||
.map(function(vv) { | ||
return indentation + vv; | ||
}) | ||
.join(EOL); | ||
} | ||
return propValue; | ||
function pad(str, value, filler) { | ||
str = String(str); | ||
var isRight = false; | ||
if (value < 0) { | ||
isRight = true; | ||
value = -value; | ||
} | ||
}; | ||
Formatter.add = function add(type, cls, sub, f) { | ||
var args = Array.prototype.slice.call(arguments); | ||
f = args.pop(); | ||
Formatter.prototype['_format_' + args.join('_')] = f; | ||
}; | ||
if (str.length < value) { | ||
var padding = new Array(value - str.length + 1).join(filler); | ||
return isRight ? str + padding : padding + str; | ||
} else { | ||
return str; | ||
} | ||
} | ||
function pad0(str, value) { | ||
return pad(str, value, '0'); | ||
} | ||
var functionNameRE = /^\s*function\s*(\S*)\s*\(/; | ||
Formatter.functionName = function functionName(f) { | ||
if(f.name) { | ||
function functionName(f) { | ||
if (f.name) { | ||
return f.name; | ||
@@ -220,14 +146,12 @@ } | ||
return name; | ||
}; | ||
} | ||
Formatter.constructorName = function(obj) { | ||
function constructorName(obj) { | ||
while (obj) { | ||
var descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor'); | ||
if (descriptor !== undefined && | ||
typeof descriptor.value === 'function') { | ||
var name = Formatter.functionName(descriptor.value); | ||
if(name !== '') { | ||
return name; | ||
} | ||
if (descriptor !== undefined && typeof descriptor.value === 'function') { | ||
var name = functionName(descriptor.value); | ||
if (name !== '') { | ||
return name; | ||
} | ||
} | ||
@@ -237,92 +161,153 @@ | ||
} | ||
}; | ||
} | ||
Formatter.getPropertyDescriptor = function(obj, value) { | ||
var INDENT = ' '; | ||
function addSpaces(str) { | ||
return indent(str, INDENT); | ||
} | ||
function typeAdaptorForEachFormat(obj, opts) { | ||
opts = opts || {}; | ||
var filterKey = opts.filterKey || function() { return true; }; | ||
var formatKey = opts.formatKey || this.format; | ||
var formatValue = opts.formatValue || this.format; | ||
var keyValueSep = typeof opts.keyValueSep !== 'undefined' ? opts.keyValueSep : ': '; | ||
this.seen.push(obj); | ||
var formatLength = 0; | ||
var pairs = []; | ||
forEach(obj, function(value, key) { | ||
if (!filterKey(key)) { | ||
return; | ||
} | ||
var formattedKey = formatKey.call(this, key); | ||
var formattedValue = formatValue.call(this, value, key); | ||
var pair = formattedKey ? (formattedKey + keyValueSep + formattedValue) : formattedValue; | ||
formatLength += pair.length; | ||
pairs.push(pair); | ||
}, this); | ||
this.seen.pop(); | ||
(opts.additionalKeys || []).forEach(function(keyValue) { | ||
var pair = keyValue[0] + keyValueSep + this.format(keyValue[1]); | ||
formatLength += pair.length; | ||
pairs.push(pair); | ||
}, this); | ||
var prefix = opts.prefix || constructorName(obj) || ''; | ||
if (prefix.length > 0) { | ||
prefix += ' '; | ||
} | ||
var lbracket, rbracket; | ||
if (Array.isArray(opts.brackets)) { | ||
lbracket = opts.brackets[0]; | ||
rbracket = opts.brackets[1]; | ||
} else { | ||
lbracket = '{'; | ||
rbracket = '}'; | ||
} | ||
var rootValue = opts.value || ''; | ||
if (pairs.length === 0) { | ||
return rootValue || (prefix + lbracket + rbracket); | ||
} | ||
if (formatLength <= this.maxLineLength) { | ||
return prefix + lbracket + ' ' + (rootValue ? rootValue + ' ' : '') + pairs.join(this.propSep + ' ') + ' ' + rbracket; | ||
} else { | ||
return prefix + lbracket + '\n' + (rootValue ? ' ' + rootValue + '\n' : '') + pairs.map(addSpaces).join(this.propSep + '\n') + '\n' + rbracket; | ||
} | ||
} | ||
function formatPlainObjectKey(key) { | ||
return typeof key === 'string' && key.match(/^[a-zA-Z_$][a-zA-Z_$0-9]*$/) ? key : this.format(key); | ||
} | ||
function getPropertyDescriptor(obj, key) { | ||
var desc; | ||
try { | ||
desc = Object.getOwnPropertyDescriptor(obj, value) || {value: obj[value]}; | ||
} catch(e) { | ||
desc = {value: e}; | ||
desc = Object.getOwnPropertyDescriptor(obj, key) || { value: obj[key] }; | ||
} catch (e) { | ||
desc = { value: e }; | ||
} | ||
return desc; | ||
}; | ||
} | ||
Formatter.generateFunctionForIndexedArray = function generateFunctionForIndexedArray(lengthProp, name, padding) { | ||
return function(value) { | ||
var max = this.byteArrayMaxLength || 50; | ||
var length = value[lengthProp]; | ||
var formattedValues = []; | ||
var len = 0; | ||
for(var i = 0; i < max && i < length; i++) { | ||
var b = value[i] || 0; | ||
var v = pad0(b.toString(16), padding); | ||
len += v.length; | ||
formattedValues.push(v); | ||
} | ||
var prefix = value.constructor.name || name || ''; | ||
if(prefix) prefix += ' '; | ||
function formatPlainObjectValue(obj, key) { | ||
var desc = getPropertyDescriptor(obj, key); | ||
if (desc.get && desc.set) { | ||
return '[Getter/Setter]'; | ||
} | ||
if (desc.get) { | ||
return '[Getter]'; | ||
} | ||
if (desc.set) { | ||
return '[Setter]'; | ||
} | ||
if(formattedValues.length === 0) | ||
return prefix + '[]'; | ||
return this.format(desc.value); | ||
} | ||
if(len <= this.maxLineLength) { | ||
return prefix + '[ ' + formattedValues.join(this.propSep + ' ') + ' ' + ']'; | ||
} else { | ||
return prefix + '[\n' + formattedValues.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; | ||
} | ||
function formatPlainObject(obj, opts) { | ||
opts = opts || {}; | ||
opts.keyValueSep = ': '; | ||
opts.formatKey = opts.formatKey || formatPlainObjectKey; | ||
opts.formatValue = opts.formatValue || function(value, key) { | ||
return formatPlainObjectValue.call(this, obj, key); | ||
}; | ||
}; | ||
return typeAdaptorForEachFormat.call(this, obj, opts); | ||
} | ||
Formatter.add('undefined', function() { return 'undefined' }); | ||
Formatter.add('null', function() { return 'null' }); | ||
Formatter.add('boolean', function(value) { return value ? 'true': 'false' }); | ||
Formatter.add('symbol', function(value) { return value.toString() }); | ||
['number', 'boolean'].forEach(function(name) { | ||
Formatter.add('object', name, function(value) { | ||
return this._formatObject(value, { | ||
additionalProperties: [['[[PrimitiveValue]]', value.valueOf()]] | ||
}); | ||
function formatWrapper1(value) { | ||
return formatPlainObject.call(this, value, { | ||
additionalKeys: [['[[PrimitiveValue]]', value.valueOf()]] | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'string', function(value) { | ||
function formatWrapper2(value) { | ||
var realValue = value.valueOf(); | ||
return this._formatObject(value, { | ||
keyFilter: function(key) { | ||
return formatPlainObject.call(this, value, { | ||
filterKey: function(key) { | ||
//skip useless indexed properties | ||
return !(key.match(/\d+/) && parseInt(key, 10) < realValue.length); | ||
}, | ||
additionalProperties: [['[[PrimitiveValue]]', realValue]] | ||
additionalKeys: [['[[PrimitiveValue]]', realValue]] | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'regexp', function(value) { | ||
return this._formatObject(value, { | ||
function formatRegExp(value) { | ||
return formatPlainObject.call(this, value, { | ||
value: String(value) | ||
}); | ||
}); | ||
} | ||
Formatter.add('number', function(value) { | ||
if(value === 0 && 1 / value < 0) return '-0'; | ||
return String(value); | ||
}); | ||
function formatFunction(value) { | ||
var obj = {}; | ||
Object.keys(value).forEach(function(key) { | ||
obj[key] = value[key]; | ||
}); | ||
return formatPlainObject.call(this, obj, { | ||
prefix: 'Function', | ||
additionalKeys: [['name', functionName(value)]] | ||
}); | ||
} | ||
Formatter.add('string', function(value) { | ||
return '\'' + JSON.stringify(value).replace(/^"|"$/g, '') | ||
.replace(/'/g, "\\'") | ||
.replace(/\\"/g, '"') + '\''; | ||
}); | ||
Formatter.add('object', function(value) { | ||
return this._formatObject(value); | ||
}); | ||
Formatter.add('object', 'arguments', function(value) { | ||
return this._formatObject(value, { | ||
prefix: 'Arguments', | ||
formatPropertyName: function(key) { | ||
if(!key.match(/\d+/)) { | ||
return this.formatPropertyName(key); | ||
function formatArray(value) { | ||
return formatPlainObject.call(this, value, { | ||
formatKey: function(key) { | ||
if (!key.match(/\d+/)) { | ||
return formatPlainObjectKey.call(this, key); | ||
} | ||
@@ -332,17 +317,17 @@ }, | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'array', function(value) { | ||
return this._formatObject(value, { | ||
formatPropertyName: function(key) { | ||
if(!key.match(/\d+/)) { | ||
return this.formatPropertyName(key); | ||
function formatArguments(value) { | ||
return formatPlainObject.call(this, value, { | ||
formatKey: function(key) { | ||
if (!key.match(/\d+/)) { | ||
return formatPlainObjectKey.call(this, key); | ||
} | ||
}, | ||
brackets: ['[', ']'] | ||
brackets: ['[', ']'], | ||
prefix: 'Arguments' | ||
}); | ||
}); | ||
} | ||
function formatDate(value, isUTC) { | ||
function _formatDate(value, isUTC) { | ||
var prefix = isUTC ? 'UTC' : ''; | ||
@@ -373,167 +358,183 @@ | ||
Formatter.add('object', 'date', function(value) { | ||
return this._formatObject(value, { value: formatDate(value, this.isUTCdate) }); | ||
}); | ||
function formatDate(value) { | ||
return formatPlainObject.call(this, value, { value: _formatDate(value, this.isUTCdate) }); | ||
} | ||
Formatter.add('function', function(value) { | ||
return this._formatObject(value, { | ||
additionalProperties: [['name', Formatter.functionName(value)]] | ||
function formatError(value) { | ||
return formatPlainObject.call(this, value, { | ||
prefix: value.name, | ||
additionalKeys: [['message', value.message]] | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'error', function(value) { | ||
return this._formatObject(value, { | ||
prefix: value.name, | ||
additionalProperties: [['message', value.message]] | ||
function generateFormatForNumberArray(lengthProp, name, padding) { | ||
return function(value) { | ||
var max = this.byteArrayMaxLength || 50; | ||
var length = value[lengthProp]; | ||
var formattedValues = []; | ||
var len = 0; | ||
for (var i = 0; i < max && i < length; i++) { | ||
var b = value[i] || 0; | ||
var v = pad0(b.toString(16), padding); | ||
len += v.length; | ||
formattedValues.push(v); | ||
} | ||
var prefix = value.constructor.name || name || ''; | ||
if (prefix) { | ||
prefix += ' '; | ||
} | ||
if (formattedValues.length === 0) { | ||
return prefix + '[]'; | ||
} | ||
if (len <= this.maxLineLength) { | ||
return prefix + '[ ' + formattedValues.join(this.propSep + ' ') + ' ' + ']'; | ||
} else { | ||
return prefix + '[\n' + formattedValues.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; | ||
} | ||
}; | ||
} | ||
function formatMap(obj) { | ||
return typeAdaptorForEachFormat.call(this, obj, { | ||
keyValueSep: ' => ' | ||
}); | ||
}); | ||
} | ||
Formatter.add('object', 'buffer', Formatter.generateFunctionForIndexedArray('length', 'Buffer', 2)); | ||
function formatSet(obj) { | ||
return typeAdaptorForEachFormat.call(this, obj, { | ||
keyValueSep: '', | ||
formatKey: function() { return ''; } | ||
}); | ||
} | ||
Formatter.add('object', 'array-buffer', Formatter.generateFunctionForIndexedArray('byteLength', 'ArrayBuffer', 2)); | ||
function genSimdVectorFormat(constructorName, length) { | ||
return function(value) { | ||
var Constructor = value.constructor; | ||
var extractLane = Constructor.extractLane; | ||
Formatter.add('object', 'typed-array', 'int8', Formatter.generateFunctionForIndexedArray('length', 'Int8Array', 2)); | ||
Formatter.add('object', 'typed-array', 'uint8', Formatter.generateFunctionForIndexedArray('length', 'Uint8Array', 2)); | ||
Formatter.add('object', 'typed-array', 'uint8clamped', Formatter.generateFunctionForIndexedArray('length', 'Uint8ClampedArray', 2)); | ||
var len = 0; | ||
var props = []; | ||
Formatter.add('object', 'typed-array', 'int16', Formatter.generateFunctionForIndexedArray('length', 'Int16Array', 4)); | ||
Formatter.add('object', 'typed-array', 'uint16', Formatter.generateFunctionForIndexedArray('length', 'Uint16Array', 4)); | ||
for (var i = 0; i < length; i ++) { | ||
var key = this.format(extractLane(value, i)); | ||
len += key.length; | ||
props.push(key); | ||
} | ||
Formatter.add('object', 'typed-array', 'int32', Formatter.generateFunctionForIndexedArray('length', 'Int32Array', 8)); | ||
Formatter.add('object', 'typed-array', 'uint32', Formatter.generateFunctionForIndexedArray('length', 'Uint32Array', 8)); | ||
if (len <= this.maxLineLength) { | ||
return constructorName + ' [ ' + props.join(this.propSep + ' ') + ' ]'; | ||
} else { | ||
return constructorName + ' [\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; | ||
} | ||
}; | ||
} | ||
//TODO add float32 and float64 | ||
function defaultFormat(value, opts) { | ||
return new Formatter(opts).format(value); | ||
} | ||
Formatter.add('object', 'promise', function() { | ||
return '[Promise]';//TODO it could be nice to inspect its state and value | ||
defaultFormat.Formatter = Formatter; | ||
defaultFormat.addSpaces = addSpaces; | ||
defaultFormat.pad0 = pad0; | ||
defaultFormat.functionName = functionName; | ||
defaultFormat.constructorName = constructorName; | ||
defaultFormat.formatPlainObjectKey = formatPlainObjectKey; | ||
// adding primitive types | ||
Formatter.addType(new t.Type(t.UNDEFINED), function() { | ||
return 'undefined'; | ||
}); | ||
Formatter.add('object', 'xhr', function() { | ||
return '[XMLHttpRequest]';//TODO it could be nice to inspect its state | ||
Formatter.addType(new t.Type(t.NULL), function() { | ||
return 'null'; | ||
}); | ||
Formatter.add('object', 'html-element', function(value) { | ||
return value.outerHTML; | ||
Formatter.addType(new t.Type(t.BOOLEAN), function(value) { | ||
return value ? 'true': 'false'; | ||
}); | ||
Formatter.add('object', 'html-element', '#text', function(value) { | ||
return value.nodeValue; | ||
Formatter.addType(new t.Type(t.SYMBOL), function(value) { | ||
return value.toString(); | ||
}); | ||
Formatter.add('object', 'html-element', '#document', function(value) { | ||
return value.documentElement.outerHTML; | ||
Formatter.addType(new t.Type(t.NUMBER), function(value) { | ||
if (value === 0 && 1 / value < 0) { | ||
return '-0'; | ||
} | ||
return String(value); | ||
}); | ||
Formatter.add('object', 'host', function() { | ||
return '[Host]'; | ||
Formatter.addType(new t.Type(t.STRING), function(value) { | ||
return '\'' + JSON.stringify(value).replace(/^"|"$/g, '') | ||
.replace(/'/g, "\\'") | ||
.replace(/\\"/g, '"') + '\''; | ||
}); | ||
Formatter.add('object', 'set', function(value) { | ||
var iter = value.values(); | ||
var len = 0; | ||
Formatter.addType(new t.Type(t.FUNCTION), formatFunction); | ||
this.seen.push(value); | ||
// plain object | ||
Formatter.addType(new t.Type(t.OBJECT), formatPlainObject); | ||
var props = []; | ||
// type wrappers | ||
Formatter.addType(new t.Type(t.OBJECT, t.NUMBER), formatWrapper1); | ||
Formatter.addType(new t.Type(t.OBJECT, t.BOOLEAN), formatWrapper1); | ||
Formatter.addType(new t.Type(t.OBJECT, t.STRING), formatWrapper2); | ||
var next = iter.next(); | ||
while(!next.done) { | ||
var val = next.value; | ||
var f = this.format(val); | ||
len += f.length; | ||
props.push(f); | ||
Formatter.addType(new t.Type(t.OBJECT, t.REGEXP), formatRegExp); | ||
Formatter.addType(new t.Type(t.OBJECT, t.ARRAY), formatArray); | ||
Formatter.addType(new t.Type(t.OBJECT, t.ARGUMENTS), formatArguments); | ||
Formatter.addType(new t.Type(t.OBJECT, t.DATE), formatDate); | ||
Formatter.addType(new t.Type(t.OBJECT, t.ERROR), formatError); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SET), formatSet); | ||
Formatter.addType(new t.Type(t.OBJECT, t.MAP), formatMap); | ||
Formatter.addType(new t.Type(t.OBJECT, t.WEAK_MAP), formatMap); | ||
Formatter.addType(new t.Type(t.OBJECT, t.WEAK_SET), formatSet); | ||
next = iter.next(); | ||
} | ||
Formatter.addType(new t.Type(t.OBJECT, t.BUFFER), generateFormatForNumberArray('length', 'Buffer', 2)); | ||
this.seen.pop(); | ||
Formatter.addType(new t.Type(t.OBJECT, t.ARRAY_BUFFER), generateFormatForNumberArray('byteLength', 'ArrayBuffer', 2)); | ||
if(props.length === 0) return 'Set {}'; | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'int8'), generateFormatForNumberArray('length', 'Int8Array', 2)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'uint8'), generateFormatForNumberArray('length', 'Uint8Array', 2)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'uint8clamped'), generateFormatForNumberArray('length', 'Uint8ClampedArray', 2)); | ||
if(len <= this.maxLineLength) { | ||
return 'Set { ' + props.join(this.propSep + ' ') + ' }'; | ||
} else { | ||
return 'Set {\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + '}'; | ||
} | ||
}); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'int16'), generateFormatForNumberArray('length', 'Int16Array', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'uint16'), generateFormatForNumberArray('length', 'Uint16Array', 4)); | ||
Formatter.add('object', 'map', function(value) { | ||
var iter = value.entries(); | ||
var len = 0; | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'int32'), generateFormatForNumberArray('length', 'Int32Array', 8)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.TYPED_ARRAY, 'uint32'), generateFormatForNumberArray('length', 'Uint32Array', 8)); | ||
this.seen.push(value); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'bool16x8'), genSimdVectorFormat('Bool16x8', 8)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'bool32x4'), genSimdVectorFormat('Bool32x4', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'bool8x16'), genSimdVectorFormat('Bool8x16', 16)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'float32x4'), genSimdVectorFormat('Float32x4', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'int16x8'), genSimdVectorFormat('Int16x8', 8)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'int32x4'), genSimdVectorFormat('Int32x4', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'int8x16'), genSimdVectorFormat('Int8x16', 16)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'uint16x8'), genSimdVectorFormat('Uint16x8', 8)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'uint32x4'), genSimdVectorFormat('Uint32x4', 4)); | ||
Formatter.addType(new t.Type(t.OBJECT, t.SIMD, 'uint8x16'), genSimdVectorFormat('Uint8x16', 16)); | ||
var props = []; | ||
var next = iter.next(); | ||
while(!next.done) { | ||
var val = next.value; | ||
var fK = this.format(val[0]); | ||
var fV = this.format(val[1]); | ||
Formatter.addType(new t.Type(t.OBJECT, t.PROMISE), function() { | ||
return '[Promise]';//TODO it could be nice to inspect its state and value | ||
}); | ||
var f; | ||
if((fK.length + fV.length + 4) <= this.maxLineLength) { | ||
f = fK + ' => ' + fV; | ||
} else { | ||
f = fK + ' =>\n' + fV; | ||
} | ||
Formatter.addType(new t.Type(t.OBJECT, t.XHR), function() { | ||
return '[XMLHttpRequest]';//TODO it could be nice to inspect its state | ||
}); | ||
len += fK.length + fV.length + 4; | ||
props.push(f); | ||
Formatter.addType(new t.Type(t.OBJECT, t.HTML_ELEMENT), function(value) { | ||
return value.outerHTML; | ||
}); | ||
next = iter.next(); | ||
} | ||
Formatter.addType(new t.Type(t.OBJECT, t.HTML_ELEMENT, '#text'), function(value) { | ||
return value.nodeValue; | ||
}); | ||
this.seen.pop(); | ||
Formatter.addType(new t.Type(t.OBJECT, t.HTML_ELEMENT, '#document'), function(value) { | ||
return value.documentElement.outerHTML; | ||
}); | ||
if(props.length === 0) return 'Map {}'; | ||
if(len <= this.maxLineLength) { | ||
return 'Map { ' + props.join(this.propSep + ' ') + ' }'; | ||
} else { | ||
return 'Map {\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + '}'; | ||
} | ||
Formatter.addType(new t.Type(t.OBJECT, t.HOST), function() { | ||
return '[Host]'; | ||
}); | ||
function simdVectorFormat(constructorName, length) { | ||
return function(value) { | ||
var Constructor = value.constructor; | ||
var extractLane = Constructor.extractLane; | ||
var len = 0; | ||
var props = []; | ||
for(var i = 0; i < length; i ++) { | ||
var key = this.format(extractLane(value, i)); | ||
len += key.length; | ||
props.push(key); | ||
} | ||
if(len <= this.maxLineLength) { | ||
return constructorName + ' [ ' + props.join(this.propSep + ' ') + ' ]'; | ||
} else { | ||
return constructorName + ' [\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; | ||
} | ||
} | ||
} | ||
Formatter.add('object', 'simd', 'bool16x8', simdVectorFormat('Bool16x8', 8)); | ||
Formatter.add('object', 'simd', 'bool32x4', simdVectorFormat('Bool32x4', 4)); | ||
Formatter.add('object', 'simd', 'bool8x16', simdVectorFormat('Bool8x16', 16)); | ||
Formatter.add('object', 'simd', 'float32x4', simdVectorFormat('Float32x4', 4)); | ||
Formatter.add('object', 'simd', 'int16x8', simdVectorFormat('Int16x8', 8)); | ||
Formatter.add('object', 'simd', 'int32x4', simdVectorFormat('Int32x4', 4)); | ||
Formatter.add('object', 'simd', 'int8x16', simdVectorFormat('Int8x16', 16)); | ||
Formatter.add('object', 'simd', 'uint16x8', simdVectorFormat('Uint16x8', 8)); | ||
Formatter.add('object', 'simd', 'uint32x4', simdVectorFormat('Uint32x4', 4)); | ||
Formatter.add('object', 'simd', 'uint8x16', simdVectorFormat('Uint8x16', 16)); | ||
Formatter.prototype.defaultFormat = Formatter.prototype._format_object; | ||
function defaultFormat(value, opts) { | ||
return new Formatter(opts).format(value); | ||
} | ||
defaultFormat.Formatter = Formatter; | ||
export default defaultFormat; |
{ | ||
"name": "should-format", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "Formatting of objects for should.js", | ||
@@ -28,5 +28,7 @@ "main": "cjs/should-format.js", | ||
"browserify": "latest", | ||
"eslint": "^3.2.2", | ||
"eslint-config-shouldjs": "^1.0.2", | ||
"mocha": "latest", | ||
"mocha-better-spec-reporter": "latest", | ||
"rollup": "0.34.1" | ||
"rollup": "0.34.7" | ||
}, | ||
@@ -40,4 +42,5 @@ "files": [ | ||
"dependencies": { | ||
"should-type": "^1.0.0" | ||
"should-type": "^1.3.0", | ||
"should-type-adaptors": "^1.0.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
32199
5
864
0
7
2
6
1
+ Addedshould-type-adaptors@^1.0.0
+ Addedshould-type-adaptors@1.1.0(transitive)
+ Addedshould-util@1.0.1(transitive)
Updatedshould-type@^1.3.0