Skip to content

Commit

Permalink
[New] option to define indentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mkls authored and ljharb committed Feb 20, 2017
1 parent 7cb5c65 commit e4472d3
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 11 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
"complexity": 0,
"func-style": [2, "declaration"],
"indent": [2, 4],
"max-lines": 1,
"max-lines-per-function": 1,
"max-params": [2, 4],
"max-statements": [2, 90],
"max-statements": [2, 100],
"max-statements-per-line": [2, { "max": 2 }],
"no-magic-numbers": 0,
"no-param-reassign": 1,
Expand Down
84 changes: 74 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ module.exports = function inspect_(obj, options, depth, seen) {
throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');
}

if (
has(opts, 'indent')
&& (
opts.indent !== '\t'
&& !(
typeof opts.indent === 'number'
&& isFinite(opts.indent)
&& parseInt(opts.indent, 10) === opts.indent
&& opts.indent >= 0
)
)
) {
throw new TypeError('options "indent" must be "\\t" or an integer 0 or greater');
}

if (typeof obj === 'undefined') {
return 'undefined';
}
Expand Down Expand Up @@ -63,17 +78,28 @@ module.exports = function inspect_(obj, options, depth, seen) {
return isArray(obj) ? '[Array]' : '[Object]';
}

var indent = getIndent(opts, depth);

if (typeof seen === 'undefined') {
seen = [];
} else if (indexOf(seen, obj) >= 0) {
return '[Circular]';
}

function inspect(value, from) {
function inspect(value, from, noIndent) {
if (from) {
seen = seen.slice();
seen.push(from);
}
if (noIndent) {
var newOpts = {
depth: opts.depth
};
if (has(opts, 'quoteStyle')) {
newOpts.quoteStyle = opts.quoteStyle;
}
return inspect_(value, newOpts, depth + 1, seen);
}
return inspect_(value, opts, depth + 1, seen);
}

Expand All @@ -98,7 +124,11 @@ module.exports = function inspect_(obj, options, depth, seen) {
}
if (isArray(obj)) {
if (obj.length === 0) { return '[]'; }
return '[ ' + arrObjKeys(obj, inspect).join(', ') + ' ]';
var xs = arrObjKeys(obj, inspect);
if (indent && !singleLineValues(xs)) {
return '[' + indentedJoin(xs, indent) + ']';
}
return '[ ' + xs.join(', ') + ' ]';
}
if (isError(obj)) {
var parts = arrObjKeys(obj, inspect);
Expand All @@ -115,16 +145,16 @@ module.exports = function inspect_(obj, options, depth, seen) {
if (isMap(obj)) {
var mapParts = [];
mapForEach.call(obj, function (value, key) {
mapParts.push(inspect(key, obj) + ' => ' + inspect(value, obj));
mapParts.push(inspect(key, obj, true) + ' => ' + inspect(value, obj));
});
return collectionOf('Map', mapSize.call(obj), mapParts);
return collectionOf('Map', mapSize.call(obj), mapParts, indent);
}
if (isSet(obj)) {
var setParts = [];
setForEach.call(obj, function (value) {
setParts.push(inspect(value, obj));
});
return collectionOf('Set', setSize.call(obj), setParts);
return collectionOf('Set', setSize.call(obj), setParts, indent);
}
if (isWeakMap(obj)) {
return weakCollectionOf('WeakMap');
Expand All @@ -145,9 +175,12 @@ module.exports = function inspect_(obj, options, depth, seen) {
return markBoxed(inspect(String(obj)));
}
if (!isDate(obj) && !isRegExp(obj)) {
var xs = arrObjKeys(obj, inspect);
if (xs.length === 0) { return '{}'; }
return '{ ' + xs.join(', ') + ' }';
var ys = arrObjKeys(obj, inspect);
if (ys.length === 0) { return '{}'; }
if (indent) {
return '{' + indentedJoin(ys, indent) + '}';
}
return '{ ' + ys.join(', ') + ' }';
}
return String(obj);
};
Expand Down Expand Up @@ -295,8 +328,39 @@ function weakCollectionOf(type) {
return type + ' { ? }';
}

function collectionOf(type, size, entries) {
return type + ' (' + size + ') {' + entries.join(', ') + '}';
function collectionOf(type, size, entries, indent) {
var joinedEntries = indent ? indentedJoin(entries, indent) : entries.join(', ');
return type + ' (' + size + ') {' + joinedEntries + '}';
}

function singleLineValues(xs) {
for (var i = 0; i < xs.length; i++) {
if (indexOf(xs[i], '\n') >= 0) {
return false;
}
}
return true;
}

function getIndent(opts, depth) {
var baseIndent;
if (opts.indent === '\t') {
baseIndent = '\t';
} else if (typeof opts.indent === 'number' && opts.indent > 0) {
baseIndent = Array(opts.indent + 1).join(' ');
} else {
return null;
}
return {
base: baseIndent,
prev: Array(depth + 1).join(baseIndent)
};
}

function indentedJoin(xs, indent) {
if (xs.length === 0) { return ''; }
var lineJoiner = '\n' + indent.prev + indent.base;
return lineJoiner + xs.join(',' + lineJoiner) + '\n' + indent.prev;
}

function arrObjKeys(obj, inspect) {
Expand Down
154 changes: 154 additions & 0 deletions test/indent-option.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
var test = require('tape');

var inspect = require('../');

test('simple object with indent', function (t) {
t.plan(1);

var obj = { a: 1, b: 2 };

var expected = [
'{',
' a: 1,',
' b: 2',
'}'
].join('\n');

t.equal(inspect(obj, { indent: 2 }), expected);
});

test('two deep object with indent', function (t) {
t.plan(1);

var obj = { a: 1, b: { c: 3, d: 4 } };

var expected = [
'{',
' a: 1,',
' b: {',
' c: 3,',
' d: 4',
' }',
'}'
].join('\n');

t.equal(inspect(obj, { indent: 2 }), expected);
});

test('simple array with all single line elements', function (t) {
t.plan(1);

var obj = [1, 2, 3, 'asdf\nsdf'];

var expected = '[ 1, 2, 3, \'asdf\\nsdf\' ]';

t.equal(inspect(obj, { indent: 2 }), expected);
});

test('array with complex elements', function (t) {
t.plan(1);

var obj = [1, { a: 1, b: { c: 1 } }, 'asdf\nsdf'];

var expected = [
'[',
' 1,',
' {',
' a: 1,',
' b: {',
' c: 1',
' }',
' },',
' \'asdf\\nsdf\'',
']'
].join('\n');

t.equal(inspect(obj, { indent: 2 }), expected);
});

test('values', function (t) {
t.plan(1);
var obj = [{}, [], { 'a-b': 5 }];

var expected = [
'[',
' {},',
' [],',
' {',
' \'a-b\': 5',
' }',
']'
].join('\n');

t.equal(inspect(obj, { indent: 2 }), expected);
});

test('Map', { skip: typeof Map !== 'function' }, function (t) {
var map = new Map();
map.set({ a: 1 }, ['b']);
map.set(3, NaN);

var expectedString = [
'Map (2) {',
' { a: 1 } => [ \'b\' ],',
' 3 => NaN',
'}'
].join('\n');

t.equal(
inspect(map, { indent: 2 }),
expectedString,
'Map keys are not indented'
);

t.equal(inspect(new Map(), { indent: 2 }), 'Map (0) {}', 'empty Map should show as empty');

var nestedMap = new Map();
nestedMap.set(nestedMap, map);
var expectedNested = [
'Map (1) {',
' [Circular] => Map (2) {',
' { a: 1 } => [ \'b\' ],',
' 3 => NaN',
' }',
'}'
].join('\n');
t.equal(inspect(nestedMap, { indent: 2 }), expectedNested, 'Map containing a Map should work');

t.end();
});

test('Set', { skip: typeof Set !== 'function' }, function (t) {
var set = new Set();
set.add({ a: 1 });
set.add(['b']);
var expectedString = [
'Set (2) {',
' {',
' a: 1',
' },',
' [ \'b\' ]',
'}'
].join('\n');
t.equal(inspect(set, { indent: 2 }), expectedString, 'new Set([{ a: 1 }, ["b"]]) should show size and contents');

t.equal(inspect(new Set(), { indent: 2 }), 'Set (0) {}', 'empty Set should show as empty');

var nestedSet = new Set();
nestedSet.add(set);
nestedSet.add(nestedSet);
var expectedNested = [
'Set (2) {',
' Set (2) {',
' {',
' a: 1',
' },',
' [ \'b\' ]',
' },',
' [Circular]',
'}'
].join('\n');
t.equal(inspect(nestedSet, { indent: 2 }), expectedNested, 'Set containing a Set should work');

t.end();
});

0 comments on commit e4472d3

Please sign in to comment.