spyglass

A value inspection tool with pretty printing, customizable colors, and powerful extension support for user-defined type inspection

npm install spyglass
8 downloads in the last month

spyglass

A value inspection tool with lots of features, based on eyes.js

Overview

Initially, this started as a simple fork of the existing eyes.js library -- I wanted to modify the behavior in a few places. However, I opted to rewrite the entire package in order to make it easier for me to work with and introduce new features.

This package is intended as a replacement for utils.inspect() to offer additional functionality and customizability. It provides color-based output using the established colors package. Custom display routines can be added for objects of any type, and the existing routines for handling builtins can be replaced with user-defined methods. Fields may be omitted from the output based on type, exact name match, or regular expression name match.

The output may be displayed in optional pretty-printed format or in a compact one-line format.

Using spyglass

Install via npm

npm install spyglass

Include the module and create an instance of the inspection object

var gls = require('spyglass');
gls = new gls();

The constructor accepts an optional options argument that can modify any of the built-in settings. These options are explained below.

To inspect an object foo and print to stdout (the default):

foo = {'a' : 'b'};
gls.inspect(foo);

produces (but with colors...)

{a : 'b'}

To add a name label to prepend to the output, add it as the second parameter. A colon will be added automatically.

gls.inspect(foo, 'Foo');

Foo: {a : 'b'}

The third parameter can be used to specify options, but they can also be passed in place of the label if one isn't required.

gls.inspect(foo, 'Foo', {'skip' : ['a']});

Foo: {}

Options

I've made an effort to select a sensible set of default options, including a color scheme chosen to match the default look of util.inspect(). However, you may wish to change some or all of the parameters. The complete list of options is:

var defaults = {
    'styles'        : default_styles,
    'skip'            : default_skip,
    'hide'            : default_hide,
    'types'            : default_subtypes,
    'handlers'        : default_handlers,
    'pretty_print'    : true,
    'stream'        : process.stdout,
    'max_itemlen'    : 40,
    'max_depth'        : 5,
    'indent'        : '   ',
    'nl'            : "\n"
};

The simple options can be described easily. pretty_print controls the use of pretty printing for output formatting. stream should be set to the stream object used for output. By default, this is stdout. Setting stream to null will cause gls.inspect() to return the formatted string rather than printing it. max_itemlen is the maximum string length for one array or object as printed before it is broken into multiple lines when pretty printing. max_depth is the maximum depth that gls.inspect() will recursively print out. indent is a string used to indent the output. Finally, nl is the string that should be used for a newline (note: this doesn't actually have to have a newline if you want to format things differnetly.

The fields styles, skip, hide, handlers, and types are more complicated, and each has its own set of defaults.

styles controls the color styles that are applied to variables based on their data types. The default values for styles are listed here:

var default_styles = {
    'label'        : ['bold'],
    'key'        : ['bold'],
    'symbol'    : ['bold', 'blue'],
    'object'    : ['blue'],
    'array'        : ['blue'],
    'function'    : ['cyan'],
    'string'    : ['green'],
    'number'    : ['yellow'],
    'boolean'    : ['yellow'],
    'regexp'    : ['red'],
    'date'        : ['magenta'],
    'null'        : ['grey'],
    'undefined'    : ['grey']
};

The first three, label, key, and symbol are special names used when printing labels, object keys, and {} or [] symbols. The rest of the styles are used to match data types as defined in the types field. Note that each style is an array. This is because styles can chain multiple effects (which is used by symbol by default). The default list of types is simply the javascript built in objects:

var default_subtypes = {
    'object'    : Object,
    'array'        : Array,
    'string'    : String,
    'regexp'    : RegExp,
    'number'    : Number,
    'boolean'    : Boolean,
    'date'        : Date
};

For the types object, the key should be the "name" of that type to be used to refer to it everywhere, and the value should be suitable for use with instanceof to determine whether the object was constructed as an instance of a given prototype.

hide is used to control which fields are hidden. It is an object with two possible keys: hidden which controls whether or not non-enumerable properties are printed. A value of true will print non-enumerable properties. The other key is types which is an array of value types to omit when printing an object. For example, the default hide value is:

var default_hide = {
    'hidden'        : true,
    'types'            : ['function', 'undefined', 'null']
};

This will print non-enumerable properties, and it will not print any fields whose values resolve to function, undefined, or null types. You may specify custom types here so long as they are also added to the types field in the general properties.

The handlers field maps from type values to callback functions that are used to determine the display for a given object type. Each handler should have the following declaration:

function handler(object, type, depth, opts)

The context for each handler will be set to the spyglass instance that is currently inspecting an object. This permits handlers to make calls to internal functions such as s() very easily. If a handler will make recursive calls to stringify(), it should be sure to respect the depth argument and limit recursion, as the recursive limit must be applied within the handler itself in order to format the output meaningfully when it is reached (and allow the most flexibility when formatting).

The handler should return a string, in all cases, representing the object that it was given. If a handler is registered for only one type, then the type argument can effectively be ignored, as it will always match. Sometimes, like in the case of simple_handler(), it is advantageous to handle multiple types with one handler, and the type value can then be forwarded to s() or used internally to differentiate between all possible types.

Finally, the skip option defaults to an empty array. Entries in skip can be strings or regular expressions, and they will be matched against object keys during property enumeration to eliminate unwanted keys. A possible skip array, therefore, could be

    [/^_/, 'id']

to hide all fields that begin with an underscore, as well as any field whose name is exactly id.

When specifying options for any of these compound types, the original types are not lost. Internally, the options are combined using _.extend() this is applied specially for all fields except skip, which will be overrwitten by a given array (skip is empty by default, so this isn't a big deal). Therefore, you do not (and really, should not) include the default values when augmenting one of the compound types with custom logic. Any matching fields will be overwritten with your values, and any new keys that you are adding will be added to the options array for the duration of the call to inspect().

The options object passed to gls.inspect() is the same as that passed to the constructor. Therefore, you can construct a spyglass object that has your preferred settings stored as a default by simply passing your options to the constructor rather than waiting until you call gls.inspect().

Examples

A few more examples to illustrate how custom options can be passed in to gls.inspect().

TODO.

npm loves you