├── .gitignore ├── yarn.lock ├── package.json ├── Readme.md ├── History.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browser-util-inspect", 3 | "version": "0.2.0", 4 | "description": "light-weight, zero-dep port of `util-inspect` suitable for the browser", 5 | "repository": "deecewan/util-inspect", 6 | "dependencies": {} 7 | } 8 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # browser-util-inspect 3 | 4 | This module contains minor modifications to the 5 | [original by Automattic](https://github.com/Automattic/util-inspect). It 6 | disregards legacy platform support and has zero dependencies, making it much 7 | lower weight. 8 | 9 | This is an extraction of Node's `inspect` utility from the `util` 10 | module, with two fundamental advantages: 11 | 12 | - Single, focused module 13 | - Ready for use in-browser 14 | 15 | ## How to use 16 | 17 | With some kind of module bundler (webpack, etc): 18 | 19 | ```js 20 | import inspect from 'browser-util-inspect'; 21 | console.log(inspect({})); 22 | ``` 23 | 24 | ## License 25 | 26 | MIT – Copyright (c) 2010-2014 Joyent, Inc. 27 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.2.0 / 2017-12-28 3 | ================== 4 | 5 | * remove old browser support 6 | * remove all dependencies 7 | 8 | ### Automattic changes 9 | 10 | 0.1.8 / 2014-02-14 11 | ================== 12 | 13 | * index: fix `document.all` type stuff 14 | 15 | 0.1.7 / 2014-02-14 16 | ================== 17 | 18 | * index: avoid double call to `Object.keys` 19 | 20 | 0.1.6 / 2014-02-14 21 | ================== 22 | 23 | * index: fix usage of `Array#reduce` for old browsers 24 | 25 | 0.1.5 / 2014-02-14 26 | ================== 27 | 28 | * index: fix usage of `indexOf` for older browsers 29 | 30 | 0.1.4 / 2014-02-14 31 | ================== 32 | 33 | * index: make `getOwnPropertyNames` and `getOwnPropertyDescriptor` 34 | optional for old browsers 35 | 36 | 0.1.3 / 2014-02-14 37 | ================== 38 | 39 | * index: add support for Array#map on older browsers 40 | 41 | 0.1.2 / 2014-02-14 42 | ================== 43 | 44 | * index: added support for Array#forEach on older browsers 45 | 46 | 0.1.1 / 2014-02-14 47 | ================== 48 | 49 | * index: added missing colors and styles 50 | 51 | 0.1.0 / 2014-02-14 52 | ================== 53 | 54 | * index: fix `_extend` usage 55 | 56 | 0.0.1 / 2014-02-14 57 | ================== 58 | 59 | * initial release 60 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module exports. 3 | */ 4 | 5 | module.exports = inspect; 6 | 7 | /** 8 | * Echos the value of a value. Trys to print the value out 9 | * in the best way possible given the different types. 10 | * 11 | * @param {Object} obj The object to print out. 12 | * @param {Object} opts Optional options object that alters the output. 13 | * @license MIT (© Joyent) 14 | */ 15 | /* legacy: obj, showHidden, depth, colors*/ 16 | 17 | function inspect(obj, opts) { 18 | // default options 19 | var ctx = { 20 | seen: [], 21 | stylize: stylizeNoColor 22 | }; 23 | // legacy... 24 | if (arguments.length >= 3) ctx.depth = arguments[2]; 25 | if (arguments.length >= 4) ctx.colors = arguments[3]; 26 | if (isBoolean(opts)) { 27 | // legacy... 28 | ctx.showHidden = opts; 29 | } else if (opts) { 30 | // got an "options" object 31 | _extend(ctx, opts); 32 | } 33 | // set default options 34 | if (isUndefined(ctx.showHidden)) ctx.showHidden = false; 35 | if (isUndefined(ctx.depth)) ctx.depth = 2; 36 | if (isUndefined(ctx.colors)) ctx.colors = false; 37 | if (isUndefined(ctx.customInspect)) ctx.customInspect = true; 38 | if (ctx.colors) ctx.stylize = stylizeWithColor; 39 | return formatValue(ctx, obj, ctx.depth); 40 | } 41 | 42 | // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 43 | inspect.colors = { 44 | 'bold' : [1, 22], 45 | 'italic' : [3, 23], 46 | 'underline' : [4, 24], 47 | 'inverse' : [7, 27], 48 | 'white' : [37, 39], 49 | 'grey' : [90, 39], 50 | 'black' : [30, 39], 51 | 'blue' : [34, 39], 52 | 'cyan' : [36, 39], 53 | 'green' : [32, 39], 54 | 'magenta' : [35, 39], 55 | 'red' : [31, 39], 56 | 'yellow' : [33, 39] 57 | }; 58 | 59 | // Don't use 'blue' not visible on cmd.exe 60 | inspect.styles = { 61 | 'special': 'cyan', 62 | 'number': 'yellow', 63 | 'boolean': 'yellow', 64 | 'undefined': 'grey', 65 | 'null': 'bold', 66 | 'string': 'green', 67 | 'date': 'magenta', 68 | // "name": intentionally not styling 69 | 'regexp': 'red' 70 | }; 71 | 72 | function stylizeNoColor(str, styleType) { 73 | return str; 74 | } 75 | 76 | function isBoolean(arg) { 77 | return typeof arg === 'boolean'; 78 | } 79 | 80 | function isUndefined(arg) { 81 | return arg === void 0; 82 | } 83 | 84 | function stylizeWithColor(str, styleType) { 85 | var style = inspect.styles[styleType]; 86 | 87 | if (style) { 88 | return '\u001b[' + inspect.colors[style][0] + 'm' + str + 89 | '\u001b[' + inspect.colors[style][1] + 'm'; 90 | } else { 91 | return str; 92 | } 93 | } 94 | 95 | function isFunction(arg) { 96 | return typeof arg === 'function'; 97 | } 98 | 99 | function isString(arg) { 100 | return typeof arg === 'string'; 101 | } 102 | 103 | function isNumber(arg) { 104 | return typeof arg === 'number'; 105 | } 106 | 107 | function isNull(arg) { 108 | return arg === null; 109 | } 110 | 111 | function hasOwn(obj, prop) { 112 | return Object.prototype.hasOwnProperty.call(obj, prop); 113 | } 114 | 115 | function isRegExp(re) { 116 | return isObject(re) && objectToString(re) === '[object RegExp]'; 117 | } 118 | 119 | function isObject(arg) { 120 | return typeof arg === 'object' && arg !== null; 121 | } 122 | 123 | function isError(e) { 124 | return isObject(e) && 125 | (objectToString(e) === '[object Error]' || e instanceof Error); 126 | } 127 | 128 | function isDate(d) { 129 | return isObject(d) && objectToString(d) === '[object Date]'; 130 | } 131 | 132 | function objectToString(o) { 133 | return Object.prototype.toString.call(o); 134 | } 135 | 136 | function arrayToHash(array) { 137 | var hash = {}; 138 | 139 | array.forEach(function(val, idx) { 140 | hash[val] = true; 141 | }); 142 | 143 | return hash; 144 | } 145 | 146 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 147 | var output = []; 148 | for (var i = 0, l = value.length; i < l; ++i) { 149 | if (hasOwn(value, String(i))) { 150 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 151 | String(i), true)); 152 | } else { 153 | output.push(''); 154 | } 155 | } 156 | keys.forEach(function(key) { 157 | if (!key.match(/^\d+$/)) { 158 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 159 | key, true)); 160 | } 161 | }); 162 | return output; 163 | } 164 | 165 | function formatError(value) { 166 | return '[' + Error.prototype.toString.call(value) + ']'; 167 | } 168 | 169 | function formatValue(ctx, value, recurseTimes) { 170 | // Provide a hook for user-specified inspect functions. 171 | // Check that value is an object with an inspect function on it 172 | if (ctx.customInspect && 173 | value && 174 | isFunction(value.inspect) && 175 | // Filter out the util module, it's inspect function is special 176 | value.inspect !== inspect && 177 | // Also filter out any prototype objects using the circular check. 178 | !(value.constructor && value.constructor.prototype === value)) { 179 | var ret = value.inspect(recurseTimes, ctx); 180 | if (!isString(ret)) { 181 | ret = formatValue(ctx, ret, recurseTimes); 182 | } 183 | return ret; 184 | } 185 | 186 | // Primitive types cannot have properties 187 | var primitive = formatPrimitive(ctx, value); 188 | if (primitive) { 189 | return primitive; 190 | } 191 | 192 | // Look up the keys of the object. 193 | var keys = Object.keys(value); 194 | var visibleKeys = arrayToHash(keys); 195 | 196 | try { 197 | if (ctx.showHidden && Object.getOwnPropertyNames) { 198 | keys = Object.getOwnPropertyNames(value); 199 | } 200 | } catch (e) { 201 | // ignore 202 | } 203 | 204 | // IE doesn't make error fields non-enumerable 205 | // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx 206 | if (isError(value) 207 | && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { 208 | return formatError(value); 209 | } 210 | 211 | // Some type of object without properties can be shortcutted. 212 | if (keys.length === 0) { 213 | if (isFunction(value)) { 214 | var name = value.name ? ': ' + value.name : ''; 215 | return ctx.stylize('[Function' + name + ']', 'special'); 216 | } 217 | if (isRegExp(value)) { 218 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 219 | } 220 | if (isDate(value)) { 221 | return ctx.stylize(Date.prototype.toString.call(value), 'date'); 222 | } 223 | if (isError(value)) { 224 | return formatError(value); 225 | } 226 | } 227 | 228 | var base = '', array = false, braces = ['{', '}']; 229 | 230 | // Make Array say that they are Array 231 | if (Array.isArray(value)) { 232 | array = true; 233 | braces = ['[', ']']; 234 | } 235 | 236 | // Make functions say that they are functions 237 | if (isFunction(value)) { 238 | var n = value.name ? ': ' + value.name : ''; 239 | base = ' [Function' + n + ']'; 240 | } 241 | 242 | // Make RegExps say that they are RegExps 243 | if (isRegExp(value)) { 244 | base = ' ' + RegExp.prototype.toString.call(value); 245 | } 246 | 247 | // Make dates with properties first say the date 248 | if (isDate(value)) { 249 | base = ' ' + Date.prototype.toUTCString.call(value); 250 | } 251 | 252 | // Make error with message first say the error 253 | if (isError(value)) { 254 | base = ' ' + formatError(value); 255 | } 256 | 257 | if (keys.length === 0 && (!array || value.length == 0)) { 258 | return braces[0] + base + braces[1]; 259 | } 260 | 261 | if (recurseTimes < 0) { 262 | if (isRegExp(value)) { 263 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 264 | } else { 265 | return ctx.stylize('[Object]', 'special'); 266 | } 267 | } 268 | 269 | ctx.seen.push(value); 270 | 271 | var output; 272 | if (array) { 273 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 274 | } else { 275 | output = keys.map(function(key) { 276 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 277 | }); 278 | } 279 | 280 | ctx.seen.pop(); 281 | 282 | return reduceToSingleString(output, base, braces); 283 | } 284 | 285 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 286 | var name, str, desc; 287 | desc = { value: void 0 }; 288 | try { 289 | // ie6 › navigator.toString 290 | // throws Error: Object doesn't support this property or method 291 | desc.value = value[key]; 292 | } catch (e) { 293 | // ignore 294 | } 295 | try { 296 | // ie10 › Object.getOwnPropertyDescriptor(window.location, 'hash') 297 | // throws TypeError: Object doesn't support this action 298 | if (Object.getOwnPropertyDescriptor) { 299 | desc = Object.getOwnPropertyDescriptor(value, key) || desc; 300 | } 301 | } catch (e) { 302 | // ignore 303 | } 304 | if (desc.get) { 305 | if (desc.set) { 306 | str = ctx.stylize('[Getter/Setter]', 'special'); 307 | } else { 308 | str = ctx.stylize('[Getter]', 'special'); 309 | } 310 | } else { 311 | if (desc.set) { 312 | str = ctx.stylize('[Setter]', 'special'); 313 | } 314 | } 315 | if (!hasOwn(visibleKeys, key)) { 316 | name = '[' + key + ']'; 317 | } 318 | if (!str) { 319 | if (ctx.seen.indexOf(desc.value) < 0) { 320 | if (isNull(recurseTimes)) { 321 | str = formatValue(ctx, desc.value, null); 322 | } else { 323 | str = formatValue(ctx, desc.value, recurseTimes - 1); 324 | } 325 | if (str.indexOf('\n') > -1) { 326 | if (array) { 327 | str = str.split('\n').map(function(line) { 328 | return ' ' + line; 329 | }).join('\n').substr(2); 330 | } else { 331 | str = '\n' + str.split('\n').map(function(line) { 332 | return ' ' + line; 333 | }).join('\n'); 334 | } 335 | } 336 | } else { 337 | str = ctx.stylize('[Circular]', 'special'); 338 | } 339 | } 340 | if (isUndefined(name)) { 341 | if (array && key.match(/^\d+$/)) { 342 | return str; 343 | } 344 | name = JSON.stringify('' + key); 345 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 346 | name = name.substr(1, name.length - 2); 347 | name = ctx.stylize(name, 'name'); 348 | } else { 349 | name = name.replace(/'/g, "\\'") 350 | .replace(/\\"/g, '"') 351 | .replace(/(^"|"$)/g, "'"); 352 | name = ctx.stylize(name, 'string'); 353 | } 354 | } 355 | 356 | return name + ': ' + str; 357 | } 358 | 359 | function formatPrimitive(ctx, value) { 360 | if (isUndefined(value)) 361 | return ctx.stylize('undefined', 'undefined'); 362 | if (isString(value)) { 363 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 364 | .replace(/'/g, "\\'") 365 | .replace(/\\"/g, '"') + '\''; 366 | return ctx.stylize(simple, 'string'); 367 | } 368 | if (isNumber(value)) 369 | return ctx.stylize('' + value, 'number'); 370 | if (isBoolean(value)) 371 | return ctx.stylize('' + value, 'boolean'); 372 | // For some reason typeof null is "object", so special case here. 373 | if (isNull(value)) 374 | return ctx.stylize('null', 'null'); 375 | } 376 | 377 | function reduceToSingleString(output, base, braces) { 378 | var numLinesEst = 0; 379 | var length = output.reduce(function(prev, cur) { 380 | numLinesEst++; 381 | if (cur.indexOf('\n') >= 0) numLinesEst++; 382 | return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; 383 | }, 0); 384 | 385 | if (length > 60) { 386 | return braces[0] + 387 | (base === '' ? '' : base + '\n ') + 388 | ' ' + 389 | output.join(',\n ') + 390 | ' ' + 391 | braces[1]; 392 | } 393 | 394 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 395 | } 396 | 397 | function _extend(origin, add) { 398 | // Don't do anything if add isn't an object 399 | if (!add || !isObject(add)) return origin; 400 | 401 | var keys = Object.keys(add); 402 | var i = keys.length; 403 | while (i--) { 404 | origin[keys[i]] = add[keys[i]]; 405 | } 406 | return origin; 407 | } 408 | --------------------------------------------------------------------------------