├── .babelrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── dist ├── console-json.js ├── console-ls.js ├── console-probe.js ├── console-yaml.js ├── index.js ├── types.js └── valid.js ├── images ├── aussieslang-json.png ├── aussieslang-ls.png ├── aussieslang-probe.png ├── aussieslang-yaml.png └── eventemitter.png ├── index.js ├── package.json ├── src ├── console-json.js ├── console-ls.js ├── console-probe.js ├── console-yaml.js ├── index.js ├── types.js └── valid.js └── tests └── console-probe.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "targets": { 5 | "node": "6.0.0" 6 | } 7 | }] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: "8" 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Grant Carthew 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # console-probe 2 | 3 | Inspect JavaScript object methods and properties in the console. 4 | 5 | [![Maintainability][cc-maintain-badge]][cc-maintain-url] 6 | [![Build Status][travisci-image]][travisci-url] 7 | [![js-standard-style][js-standard-image]][js-standard-url] 8 | [![Patreon Donation][patreon-image]][patreon-url] 9 | 10 | ![Event Emitter Example][example-eventemitter-image] 11 | 12 | [![NPM][nodei-npm-image]][nodei-npm-url] 13 | 14 | Provides colourful functions to inspect JavaScript objects. 15 | 16 | * The `probe()` function outputs a prototype hierarchy tree to the console. 17 | * The `json()` function safely writes a stringified object output to the console. 18 | * The `yaml()` function converts objects into yaml format and outputs to the console. 19 | * The `ls()` function converts objects into a colourful format and outputs to the console. 20 | 21 | ## Installing 22 | 23 | * Node: v6.0.0 or later. 24 | * Browser: Not tested 25 | 26 | ```sh 27 | npm install --save-dev console-probe 28 | ``` 29 | 30 | ## Quick Start 31 | 32 | __Not recommended for production environments__ 33 | 34 | 35 | ```js 36 | 37 | const cp = require('./console-probe') 38 | const arrLen = 2 39 | 40 | const aussieSlang = { 41 | 'name': 'Aussie Slang Words', 42 | 'gday': Infinity, 43 | 'maccas': Number.NaN, 44 | 'arvo': undefined, 45 | 'straya': null, 46 | 'footy': {specky: true}, 47 | 'biccy': (size, toppings) => {}, 48 | 'servo': true, 49 | 'choccy': Symbol('Mmmmm...'), 50 | 'bottle-o': Error('Cheers mate! My shout next'), 51 | 'tinny': 42, 52 | 'coppa': new Date(), 53 | 'tradie': 'She\'ll be right mate?', 54 | 'postie': /a.long.regexp.that.keeps.giving/, 55 | 'garbo': [1, 2, 3], 56 | 'muso': new Int8Array(arrLen), 57 | 'cabbie': new Uint8Array(arrLen), 58 | 'ambo': new Uint8ClampedArray(arrLen), 59 | 'prezzie': new Int16Array(arrLen), 60 | 'chrissie': new Uint16Array(arrLen), 61 | 'cuppa': new Int32Array(arrLen), 62 | 'mate': new Uint32Array(arrLen), 63 | 'snag': new Float32Array(arrLen), 64 | 'drongo': new Float64Array(arrLen), 65 | 'fairDinkum': new Map([['foo', 'bar']]), 66 | 'bonza': new Set([['foo', 'bar']]), 67 | 'tooRight': new WeakMap(), 68 | 'dunny': new WeakSet(), 69 | 'cobber': new ArrayBuffer(arrLen), 70 | 'barbie': new SharedArrayBuffer(arrLen), 71 | 'stickybeak': Atomics, 72 | 'stoked': new DataView(new ArrayBuffer(arrLen)), 73 | 'ripper': Promise.resolve(), 74 | 'mongrel': (function * () {})(), 75 | 'holyDooley': function * (foo, bar) {}, 76 | 'roo': async function (foo, bar) {} 77 | } 78 | const secret = Symbol('Hidden Property') 79 | aussieSlang[secret] = 'Bogan' 80 | 81 | // Calling console-probe functions. 82 | cp.probe(aussieSlang) // Writes a prototype tree to the console 83 | cp.json(aussieSlang) // Writes a JSON formatted object to the console 84 | cp.yaml(aussieSlang) // Writes a YAML formatted object to the console 85 | cp.ls(aussieSlang) // Writes a formatted object to the console 86 | 87 | // Adding console-probe functions to the console. 88 | console.probe(aussieSlang) // Throws exception 'console.probe is not a function' 89 | console.json(aussieSlang) // Throws exception 'console.json is not a function' 90 | console.yaml(aussieSlang) // Throws exception 'console.yaml is not a function' 91 | console.ls(aussieSlang) // Throws exception 'console.ls is not a function' 92 | cp.apply() 93 | console.probe(aussieSlang) // Writes a prototype tree to the console 94 | console.json(aussieSlang) // Writes a JSON formatted object to the console 95 | console.yaml(aussieSlang) // Writes a YAML formatted object to the console 96 | console.ls(aussieSlang) // Writes a formatted object to the console 97 | 98 | // Adding console-probe functions to an object. 99 | const foo = {} 100 | cp.apply(foo) 101 | foo.probe(aussieSlang) // Writes prototype tree to the console 102 | foo.json(aussieSlang) // Writes a JSON formatted object to the console 103 | foo.yaml(aussieSlang) // Writes a YAML formatted object to the console 104 | foo.ls(aussieSlang) // Writes a formatted object to the console 105 | 106 | ``` 107 | 108 | The above code will produce the following results when it writes to the console. 109 | 110 | ### The `probe` function output: 111 | 112 | _Note: Type detection errors will display as `[Unknown]`._ 113 | 114 | ![Example Probe Output][example-probe-image] 115 | 116 | ### The `json` function output: 117 | 118 | ![Example Json Output][example-json-image] 119 | 120 | ### The `yaml` function output: 121 | 122 | ![Example Yaml Output][example-yaml-image] 123 | 124 | ### The `ls` function output: 125 | 126 | ![Example ls Output][example-ls-image] 127 | 128 | ## Rational 129 | 130 | There are many amazing packages on `npm`. Many of those packages are not well documented. Rather than go straight to reading source code I wrote `console-probe` to inspect objects and discover methods and properties. Using Node.js with inspect is often a better approach however I don't always have it running; this is when `console-probe` comes in handy. 131 | 132 | ## Function 133 | 134 | The `console-probe` package provides four functions that will write to the console: 135 | 136 | * `probe(obj)`: The probe function uses `Object.getOwnPropertyNames()` and `Object.getOwnPropertySymbols()` to enumerate the members of an object through its prototype hierarchy. Using the type list from [MDN][jstypes-url] the types are detected. After a little formatting the result is written to the console using the [archy][archy-url] package with some colour added by [chalk][chalk-url]. 137 | * `json(obj, replacer, spacer, color)`: Uses [fast-safe-stringify][fss-url] and [json-colorizer][json-colorizer-url] to safely write the stringified object out to the console. 138 | * `yaml(obj, options, indentation)`: A simple wrapper around the [prettyjson][prettyjson-url] package render function. 139 | * `ls(obj)`: A simple wrapper around the [jsome][jsome-url] package render function. 140 | 141 | ## API 142 | 143 | ### `probe` Function 144 | 145 | __Description:__ Inspects the passed objects properties and methods, then the prototype of the passed object, and so on till the last prototype is analyzed. A tree of the properties and methods on each prototype is written to the console. 146 | 147 | __Method Signature:__ `probe(object)` 148 | 149 | __Parameter:__ `object` can be any JavaScript type. 150 | 151 | __Details:__ 152 | 153 | * Passing either `null` or `undefined` will write `[console-probe] Invalid Type:` to the console. 154 | * String values with newline characters are stripped from string stubs. 155 | 156 | __Example:__ 157 | 158 | ```js 159 | const cp = require('console-probe') 160 | cp.probe({ key: 'value' }) 161 | // Writes the object prototype hierarchy to the console 162 | // See above for an example of the output 163 | ``` 164 | 165 | ### `json` Function 166 | 167 | __Description:__ This function simply calls [fast-safe-stringify][fss-url] and then adds color via [json-colorizer][json-colorizer-url]. Once that is done it writes the result to the console. 168 | 169 | __Method Signature:__ `json(object, replacer, spacer, color)` 170 | 171 | __Parameter:__ 172 | 173 | * `object` can be any object you wish to stringify. 174 | * `replacer` alters the behavior of the stringification process. 175 | * `spacer` inserts white space into the output JSON string for readability purposes. 176 | * `color` enables customization of the colour displayed. 177 | 178 | __Details:__ 179 | 180 | * The `json` function defaults to `replacer = null` and `spacer = 2`. 181 | * See both [fast-safe-stringify][fss-url] and [JSON.stringify][json-stringify-url] for more details. 182 | * Change the color displayed using a color object from the [json-colorizer][json-colorizer-url] options. 183 | 184 | __Example:__ 185 | 186 | ```js 187 | const cp = require('console-probe') 188 | cp.json({ key: 'value' }) 189 | // Outputs the following to the console: 190 | // { 191 | // "key": "value" 192 | // } 193 | ``` 194 | 195 | ### `yaml` Function 196 | 197 | __Description:__ This function wraps the [prettyjson][prettyjson-url] render function and writes the result to the console. The result is a colorized formatted [YAML][yaml-url] representation of the object data. 198 | 199 | __Signature:__ `yaml(object, options, indentation)` 200 | 201 | __Parameter:__ 202 | 203 | * `object` can be any object you wish to display in [YAML][yaml-url] format. 204 | * `options` should hold options for the [prettyjson][prettyjson-url] render function. 205 | * `indentation` controls the indentation for the YAML output. 206 | 207 | __Details:__ 208 | 209 | * The `yaml` function is simply a wrapper around the [prettyjson][prettyjson-url] package. 210 | * See the [prettyjson][prettyjson-url] documentation and code for the options and indentation. 211 | 212 | __Example:__ 213 | 214 | ```js 215 | const cp = require('console-probe') 216 | cp.yaml({ key: 'value' }) 217 | // Outputs the following to the console: 218 | // key: value 219 | ``` 220 | 221 | ### `ls` Function 222 | 223 | __Description:__ This function wraps the [jsome][jsome-url] render function and writes the result to the console. The result is a colorized formatted representation of the object data. 224 | 225 | __Signature:__ `ls(object)` 226 | 227 | __Parameter:__ 228 | 229 | * `object` can be any object you wish to display. 230 | 231 | __Details:__ 232 | 233 | * The `ls` function is simply a wrapper around the [jsome][jsome-url] package. 234 | * See the [jsome][jsome-url] documentation for more detail. 235 | 236 | __Example:__ 237 | 238 | ```js 239 | const cp = require('console-probe') 240 | cp.ls({ key: 'value' }) 241 | // Outputs the following to the console: 242 | // { 243 | // key: "value" 244 | // } 245 | ``` 246 | ### `apply` Function 247 | 248 | __Signature:__ `apply(object)` 249 | 250 | __Parameter:__ `object` can be any object you would like to add `console-probe` functions to. 251 | 252 | __Details:__ 253 | 254 | * The `apply` function is a convenience method to add the `console-probe` functions to an object. 255 | * If no `object` is passed to the `apply` function then the `console-probe` functions will be added to the `console` object. 256 | * Passing an object, such as a logger, will add the `console-probe` functions to the object. 257 | 258 | __Example:__ 259 | 260 | ```js 261 | const cp = require('console-probe') 262 | cp.apply() 263 | // console now has a probe, json, yaml, and ls functions. 264 | 265 | const foo = {} 266 | cp.apply(foo) 267 | // foo now has a probe, json, yaml, and ls functions. 268 | ``` 269 | 270 | Another approach to simply augment the console: 271 | 272 | ```js 273 | require('console-probe').apply() 274 | // console.probe, console.json, console.yaml, and console.ls are now ready for use. 275 | ``` 276 | 277 | ## About the Owner 278 | 279 | I, Grant Carthew, am a technologist, trainer, and Dad from Queensland, Australia. I work on code in a number of personal projects and when the need arises I build my own packages. 280 | 281 | This project exists because I wanted to inspect objects from the console. 282 | 283 | Everything I do in open source is done in my own time and as a contribution to the open source community. 284 | 285 | If you are using my projects and would like to thank me or support me, please click the Patreon link below. 286 | 287 | [![Patreon Donation][patreon-image]][patreon-url] 288 | 289 | See my [other projects on NPM](https://www.npmjs.com/~grantcarthew). 290 | 291 | ## Contributing 292 | 293 | 1. Fork it! 294 | 2. Create your feature branch: `git checkout -b my-new-feature` 295 | 3. Commit your changes: `git commit -am 'Add some feature'` 296 | 4. Push to the branch: `git push origin my-new-feature` 297 | 5. Submit a pull request :D 298 | 299 | ## Change Log 300 | 301 | - v3.3.2 [2019-10-14]: Added 'name' to the name getter. 302 | - v3.3.1 [2019-10-14]: Fixed Getter support (#5). Removed NSP from readme. 303 | - v3.3.0 [2018-07-05]: Added new method `ls`. Fixed README badges. Fixed null/undefined error. 304 | - v3.2.1 [2018-07-05]: Added `BigInt` type support. Updated dependencies. 305 | - v3.2.0 [2018-03-02]: Multiple type support. Probe format updated. 306 | - v3.1.0 [2018-02-19]: Added colour to json. Added yaml function. 307 | - v3.0.0 [2018-02-18]: Added json function. Improved API. Removed newline chrs. 308 | - v2.0.4 [2018-01-29]: Changed node label format. 309 | - v2.0.3 [2018-01-26]: Fix example image url. 310 | - v2.0.2 [2018-01-26]: Added support for arrays and values. Fixed sort. 311 | - v2.0.1 [2018-01-25]: Added repository url to package.json. 312 | - v2.0.0 [2018-01-24]: Changed API. Improved type support. 313 | - v1.0.2 [2018-01-23]: Updated Readme. 314 | - v1.0.1 [2018-01-23]: Updated NSP link. 315 | - v1.0.0 [2018-01-23]: Initial release. 316 | 317 | [cc-maintain-badge]: https://api.codeclimate.com/v1/badges/805e88a221e165ecda12/maintainability 318 | [cc-maintain-url]: https://codeclimate.com/github/grantcarthew/node-console-probe/maintainability 319 | [travisci-image]: https://travis-ci.org/grantcarthew/node-console-probe.svg?branch=master 320 | [travisci-url]: https://travis-ci.org/grantcarthew/node-console-probe 321 | [js-standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg 322 | [js-standard-url]: http://standardjs.com/ 323 | [mppg-url]: https://github.com/grantcarthew/node-console-probe 324 | [bithound-code-image]: https://www.bithound.io/github/grantcarthew/node-console-probe/badges/code.svg 325 | [bithound-code-url]: https://www.bithound.io/github/grantcarthew/node-console-probe 326 | [patreon-image]: https://img.shields.io/badge/patreon-donate-yellow.svg 327 | [patreon-url]: https://www.patreon.com/grantcarthew 328 | [nodei-npm-image]: https://nodei.co/npm/console-probe.png?downloads=true&downloadRank=true&stars=true 329 | [nodei-npm-url]: https://nodei.co/npm/console-probe/ 330 | [archy-url]: https://www.npmjs.com/package/archy 331 | [chalk-url]: https://www.npmjs.com/package/chalk 332 | [fss-url]: https://www.npmjs.com/package/fast-safe-stringify 333 | [example-eventemitter-image]: https://cdn.rawgit.com/grantcarthew/node-console-probe/b7f56e39/images/eventemitter.png 334 | [example-probe-image]: https://cdn.rawgit.com/grantcarthew/node-console-probe/b7f56e39/images/aussieslang-probe.png 335 | [example-json-image]: https://cdn.rawgit.com/grantcarthew/node-console-probe/b7f56e39/images/aussieslang-json.png 336 | [example-yaml-image]: https://cdn.rawgit.com/grantcarthew/node-console-probe/b7f56e39/images/aussieslang-yaml.png 337 | [example-ls-image]: https://cdn.rawgit.com/grantcarthew/node-console-probe/4ea69e0c/images/aussieslang-ls.png 338 | [json-stringify-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify 339 | [prettyjson-url]: https://www.npmjs.com/package/prettyjson 340 | [json-colorizer-url]: https://www.npmjs.com/package/json-colorizer 341 | [yaml-url]: http://yaml.org/ 342 | [jsome-url]: https://www.npmjs.com/package/jsome 343 | [jstypes-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects 344 | -------------------------------------------------------------------------------- /dist/console-json.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fastSafeStringify = require('fast-safe-stringify'); 4 | const jsonColorizer = require('json-colorizer'); 5 | const valid = require('./valid'); 6 | 7 | module.exports = function json(obj, replacer = null, spacer = 2, color = {}) { 8 | if (!valid(obj)) { 9 | return; 10 | } 11 | const asString = fastSafeStringify(obj, replacer, spacer); 12 | console.log(jsonColorizer(asString, color)); 13 | }; -------------------------------------------------------------------------------- /dist/console-ls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const jsome = require('jsome'); 4 | const valid = require('./valid'); 5 | // jsome.level.show = true 6 | 7 | module.exports = function ls(obj) { 8 | if (!valid(obj)) { 9 | return; 10 | } 11 | jsome(obj); 12 | }; -------------------------------------------------------------------------------- /dist/console-probe.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const chalk = require('chalk'); 4 | const stripAnsi = require('strip-ansi'); 5 | const archy = require('archy'); 6 | const types = require('./types'); 7 | const valid = require('./valid'); 8 | 9 | module.exports = function probe(obj) { 10 | if (!valid(obj)) { 11 | return; 12 | } 13 | 14 | let tree = null; 15 | let currentNode = newNode('root'); 16 | 17 | for (; obj != null; obj = Object.getPrototypeOf(obj)) { 18 | let node = newNode(genHeader(obj)); 19 | node.nodes = Object.getOwnPropertyNames(obj); 20 | node.nodes.push(...Object.getOwnPropertySymbols(obj)); 21 | node = processNode(node, obj); 22 | tree = tree || node; 23 | currentNode.nodes.push(node); 24 | currentNode = node; 25 | } 26 | console.log(archy(tree)); 27 | }; 28 | 29 | function processNode(node, obj) { 30 | for (let i = 0; i < node.nodes.length; i++) { 31 | let focusObj = null; 32 | let propertyIsGetter = false; 33 | let type; 34 | try { 35 | propertyIsGetter = isGetter(obj, node.nodes[i]); 36 | focusObj = obj[node.nodes[i]]; 37 | type = getTypeString(focusObj); 38 | } catch (err) { 39 | type = propertyIsGetter ? types.Getter : types.Unknown; 40 | focusObj = err; 41 | } 42 | node.nodes[i] = getNodeString(type, focusObj, node.nodes[i]); 43 | } 44 | node.nodes.sort((a, b) => { 45 | return stripAnsi(a).localeCompare(stripAnsi(b)); 46 | }); 47 | return node; 48 | } 49 | 50 | function getNodeString(type, obj, node) { 51 | let prefix = applyChalk(type, `[${type}]`); 52 | const postfix = genPostfix(type, obj); 53 | const isSymbolKey = getTypeString(node) === types.Symbol; 54 | if (isSymbolKey) { 55 | const symDesc = getSymbolDescription(node); 56 | prefix = applyChalk(types.Symbol, `[${types.Symbol}]`) + prefix; 57 | if (symDesc) { 58 | return `${prefix} ${symDesc} ${postfix}`; 59 | } else { 60 | return `${prefix} ${postfix}`; 61 | } 62 | } 63 | return `${prefix} ${node} ${postfix}`; 64 | } 65 | 66 | function newNode(label) { 67 | return { 68 | label, 69 | nodes: [] 70 | }; 71 | } 72 | 73 | function genHeader(obj) { 74 | const constName = obj.constructor.name ? obj.constructor.name : ''; 75 | let objName = isGetter(obj, 'name') ? applyChalk(types.Getter, `[${types.Getter}] name ()`) : ''; 76 | try { 77 | objName = obj.name && obj.name; 78 | } catch (err) {} 79 | const objSignature = genSignature(obj); 80 | let header = constName ? `[${constName}]` : `[${typeof obj}]`; 81 | header = chalk.red(header); 82 | header += objName ? ` ${objName}` : ''; 83 | header += objSignature ? ` ${objSignature}` : ''; 84 | return header; 85 | } 86 | 87 | function isGetter(obj, propertyName) { 88 | const descriptor = Object.getOwnPropertyDescriptor(obj, propertyName); 89 | return !!(descriptor && descriptor.get && typeof descriptor.get === 'function'); 90 | } 91 | 92 | function getTypeString(obj) { 93 | if (Number.isNaN(obj)) return types.NaN; 94 | return Object.prototype.toString.call(obj).slice(8, -1); 95 | } 96 | 97 | function genPostfix(type, obj) { 98 | let postfix = ''; 99 | let symDesc = ''; 100 | switch (type) { 101 | case types.Infinity: 102 | case types.NaN: 103 | case types.Undefined: 104 | case types.Null: 105 | break; 106 | case types.Object: 107 | postfix = applyChalk(type, `[keys: ${Object.getOwnPropertyNames(obj).length}]`); 108 | break; 109 | case types.Function: 110 | case types.GeneratorFunction: 111 | case types.AsyncFunction: 112 | postfix = applyChalk(type, genSignature(obj)); 113 | break; 114 | case types.Boolean: 115 | postfix = applyChalk(type, `[${obj.toString()}]`); 116 | break; 117 | case types.Symbol: 118 | symDesc = getSymbolDescription(obj); 119 | if (symDesc) { 120 | postfix = applyChalk(type, `[desc: ${symDesc}]`); 121 | } 122 | break; 123 | case types.Error: 124 | postfix = obj.message && applyChalk(type, `[${cleanString(obj.message)}]`); 125 | break; 126 | case types.Number: 127 | case types.BigInt: 128 | postfix = applyChalk(type, `[${obj.toString()}]`); 129 | break; 130 | case types.Date: 131 | postfix = applyChalk(type, `[${obj.toString()}]`); 132 | break; 133 | case types.String: 134 | postfix = applyChalk(type, `[${cleanString(obj)}]`); 135 | break; 136 | case types.RegExp: 137 | postfix = applyChalk(type, `[${limitString(obj.toString())}]`); 138 | break; 139 | case types.Array: 140 | case types.Int8Array: 141 | case types.Uint8Array: 142 | case types.Uint8ClampedArray: 143 | case types.Int16Array: 144 | case types.Uint16Array: 145 | case types.Int32Array: 146 | case types.Uint32Array: 147 | case types.Float32Array: 148 | case types.Float64Array: 149 | postfix = applyChalk(type, `[len: ${obj.length}]`); 150 | break; 151 | case types.Map: 152 | case types.Set: 153 | postfix = applyChalk(type, `[size: ${obj.size}]`); 154 | break; 155 | case types.ArrayBuffer: 156 | case types.SharedArrayBuffer: 157 | case types.DataView: 158 | postfix = applyChalk(type, `[len: ${obj.byteLength}]`); 159 | break; 160 | default: 161 | break; 162 | } 163 | return postfix; 164 | } 165 | 166 | function cleanString(value) { 167 | const str = value.replace(/(?:\r\n|\r|\n)/g, ''); 168 | return limitString(str); 169 | } 170 | 171 | function limitString(value) { 172 | const limit = 15; 173 | return value.length > limit ? value.substring(0, limit) + '...' : value; 174 | } 175 | 176 | function getSymbolDescription(sym) { 177 | return String(sym).slice(7, -1); 178 | } 179 | 180 | function applyChalk(type, str) { 181 | let result; 182 | switch (type) { 183 | // Null Types 184 | case types.Infinity: 185 | case types.NaN: 186 | case types.Undefined: 187 | case types.Null: 188 | result = str; // No colour 189 | break; 190 | // Objects and Properties 191 | case types.Object: 192 | case types.Symbol: 193 | case types.Date: 194 | result = chalk.yellow(str); 195 | break; 196 | // Collections and Arrays 197 | case types.Array: 198 | case types.Int8Array: 199 | case types.Uint8Array: 200 | case types.Uint8ClampedArray: 201 | case types.Int16Array: 202 | case types.Uint16Array: 203 | case types.Int32Array: 204 | case types.Uint32Array: 205 | case types.Float32Array: 206 | case types.Float64Array: 207 | case types.Map: 208 | case types.Set: 209 | case types.WeakMap: 210 | case types.WeakSet: 211 | result = chalk.blue(str); 212 | break; 213 | // Structured Data and Boolean 214 | case types.Boolean: 215 | case types.ArrayBuffer: 216 | case types.SharedArrayBuffer: 217 | case types.Atomics: 218 | case types.DataView: 219 | result = chalk.cyan(str); 220 | break; 221 | // Functions and Control Objects 222 | case types.Getter: 223 | case types.Function: 224 | case types.Promise: 225 | case types.Generator: 226 | case types.GeneratorFunction: 227 | case types.AsyncFunction: 228 | result = chalk.green(str); 229 | break; 230 | // Number Types 231 | case types.Number: 232 | case types.BigInt: 233 | result = chalk.blue(str); 234 | break; 235 | // Strings 236 | case types.String: 237 | case types.RegExp: 238 | result = chalk.magenta(str); 239 | break; 240 | // Errors 241 | case types.Error: 242 | result = chalk.red(str); 243 | break; 244 | default: 245 | result = str; 246 | break; 247 | } 248 | return result; 249 | } 250 | 251 | function genSignature(obj) { 252 | let funString = ''; 253 | if (!isFunction(obj)) { 254 | return funString; 255 | } 256 | try { 257 | funString = Function.prototype.toString.call(obj); 258 | funString = funString.slice(funString.indexOf('('), funString.indexOf(')') + 1); 259 | } catch (err) {} 260 | return funString.slice(funString.indexOf('('), funString.indexOf(')') + 1); 261 | } 262 | 263 | function isFunction(obj) { 264 | const type = getTypeString(obj); 265 | return type === types.Function || type === types.GeneratorFunction || type === types.AsyncFunction; 266 | } -------------------------------------------------------------------------------- /dist/console-yaml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const prettyJson = require('prettyjson'); 4 | const valid = require('./valid'); 5 | 6 | module.exports = function yaml(obj, options, indentation) { 7 | if (!valid(obj)) { 8 | return; 9 | } 10 | console.log(prettyJson.render(obj, options, indentation)); 11 | }; -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const probe = require('./console-probe'); 4 | const json = require('./console-json'); 5 | const yaml = require('./console-yaml'); 6 | const ls = require('./console-ls'); 7 | 8 | module.exports = Object.freeze({ 9 | apply, 10 | probe, 11 | json, 12 | yaml, 13 | ls 14 | }); 15 | 16 | function apply(obj) { 17 | if (obj == null) { 18 | global.console.probe = probe; 19 | global.console.json = json; 20 | global.console.yaml = yaml; 21 | global.console.ls = ls; 22 | } else { 23 | obj.probe = probe; 24 | obj.json = json; 25 | obj.yaml = yaml; 26 | obj.ls = ls; 27 | } 28 | } 29 | 30 | // Adding BigInt support for JSON.stringify() 31 | if (global.BigInt) { 32 | global.BigInt.prototype.toJSON = function (key) { 33 | return this.toString(); 34 | }; 35 | } -------------------------------------------------------------------------------- /dist/types.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = Object.freeze({ 4 | // Type Errors 5 | Unknown: 'Unknown', 6 | Getter: 'Getter', 7 | 8 | // Value Properties 9 | Infinity: 'Infinity', 10 | NaN: 'NaN', 11 | Undefined: 'Undefined', 12 | Null: 'Null', 13 | 14 | // Fundamental Objects 15 | Object: 'Object', 16 | Function: 'Function', 17 | Boolean: 'Boolean', 18 | Symbol: 'Symbol', 19 | Error: 'Error', 20 | 21 | // Numbers and Dates 22 | Number: 'Number', 23 | BigInt: 'BigInt', 24 | Date: 'Date', 25 | 26 | // Text Processing 27 | String: 'String', 28 | RegExp: 'RegExp', 29 | 30 | // Indexed Collections 31 | Array: 'Array', 32 | Int8Array: 'Int8Array', 33 | Uint8Array: 'Uint8Array', 34 | Uint8ClampedArray: 'Uint8ClampedArray', 35 | Int16Array: 'Int16Array', 36 | Uint16Array: 'Uint16Array', 37 | Int32Array: 'Int32Array', 38 | Uint32Array: 'Uint32Array', 39 | Float32Array: 'Float32Array', 40 | Float64Array: 'Float64Array', 41 | 42 | // Keyed Collections 43 | Map: 'Map', 44 | Set: 'Set', 45 | WeakMap: 'WeakMap', 46 | WeakSet: 'WeakSet', 47 | 48 | // Structured Data 49 | ArrayBuffer: 'ArrayBuffer', 50 | SharedArrayBuffer: 'SharedArrayBuffer', 51 | Atomics: 'Atomics', 52 | DataView: 'DataView', 53 | 54 | // Control Abstraction Objects 55 | Promise: 'Promise', 56 | Generator: 'Generator', 57 | GeneratorFunction: 'GeneratorFunction', 58 | AsyncFunction: 'AsyncFunction' 59 | }); -------------------------------------------------------------------------------- /dist/valid.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const chalk = require('chalk'); 4 | 5 | module.exports = function valid(value) { 6 | if (value == null) { 7 | let message = chalk.red('[console-probe] Cannot inspect: '); 8 | message += Object.prototype.toString.call(value); 9 | console.log(message); 10 | return false; 11 | } 12 | return true; 13 | }; -------------------------------------------------------------------------------- /images/aussieslang-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantcarthew/node-console-probe/e60f5064eb5a058639d4ddb0ee0d130489db5dd6/images/aussieslang-json.png -------------------------------------------------------------------------------- /images/aussieslang-ls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantcarthew/node-console-probe/e60f5064eb5a058639d4ddb0ee0d130489db5dd6/images/aussieslang-ls.png -------------------------------------------------------------------------------- /images/aussieslang-probe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantcarthew/node-console-probe/e60f5064eb5a058639d4ddb0ee0d130489db5dd6/images/aussieslang-probe.png -------------------------------------------------------------------------------- /images/aussieslang-yaml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantcarthew/node-console-probe/e60f5064eb5a058639d4ddb0ee0d130489db5dd6/images/aussieslang-yaml.png -------------------------------------------------------------------------------- /images/eventemitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantcarthew/node-console-probe/e60f5064eb5a058639d4ddb0ee0d130489db5dd6/images/eventemitter.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist') 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "console-probe", 3 | "version": "3.3.2", 4 | "description": "Inspect JavaScript object methods and properties in the console.", 5 | "main": "console-probe.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/grantcarthew/node-console-probe.git" 9 | }, 10 | "scripts": { 11 | "clean": "del dist", 12 | "test": "jest", 13 | "watch": "jest --watch", 14 | "lint": "standard", 15 | "prepublish": "npm run build", 16 | "build": "npm run clean && standard && babel src -d dist && npm test", 17 | "upgrade": "npm run upgrade:rm && npm run upgrade:ncu && npm run upgrade:npm-install", 18 | "upgrade:rm": "rm node_modules -Rf", 19 | "upgrade:ncu": "npm-check-updates -u", 20 | "upgrade:npm-install": "npm install", 21 | "t": "node t.js" 22 | }, 23 | "keywords": [ 24 | "console", 25 | "object", 26 | "inspect", 27 | "probe", 28 | "discover", 29 | "api" 30 | ], 31 | "author": "Grant Carthew", 32 | "license": "MIT", 33 | "standard": { 34 | "globals": [ 35 | "test", 36 | "expect", 37 | "jest", 38 | "beforeAll", 39 | "afterAll", 40 | "describe", 41 | "SharedArrayBuffer", 42 | "Atomics", 43 | "BigInt" 44 | ], 45 | "ignore": [ 46 | "dist" 47 | ] 48 | }, 49 | "dependencies": { 50 | "archy": "^1.0.0", 51 | "chalk": "^2.4.2", 52 | "fast-safe-stringify": "^2.0.7", 53 | "jsome": "^2.5.0", 54 | "json-colorizer": "^2.2.1", 55 | "prettyjson": "^1.2.1", 56 | "strip-ansi": "^5.2.0" 57 | }, 58 | "devDependencies": { 59 | "babel-cli": "^6.26.0", 60 | "babel-preset-env": "^1.7.0", 61 | "del-cli": "^3.0.0", 62 | "jest": "^24.9.0", 63 | "nodemon": "^1.19.3", 64 | "npm-check-updates": "^3.1.24", 65 | "standard": "^14.3.1" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/console-json.js: -------------------------------------------------------------------------------- 1 | const fastSafeStringify = require('fast-safe-stringify') 2 | const jsonColorizer = require('json-colorizer') 3 | const valid = require('./valid') 4 | 5 | module.exports = function json (obj, replacer = null, spacer = 2, color = {}) { 6 | if (!valid(obj)) { return } 7 | const asString = fastSafeStringify(obj, replacer, spacer) 8 | console.log(jsonColorizer(asString, color)) 9 | } 10 | -------------------------------------------------------------------------------- /src/console-ls.js: -------------------------------------------------------------------------------- 1 | const jsome = require('jsome') 2 | const valid = require('./valid') 3 | // jsome.level.show = true 4 | 5 | module.exports = function ls (obj) { 6 | if (!valid(obj)) { return } 7 | jsome(obj) 8 | } 9 | -------------------------------------------------------------------------------- /src/console-probe.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const stripAnsi = require('strip-ansi') 3 | const archy = require('archy') 4 | const types = require('./types') 5 | const valid = require('./valid') 6 | 7 | module.exports = function probe (obj) { 8 | if (!valid(obj)) { return } 9 | 10 | let tree = null 11 | let currentNode = newNode('root') 12 | 13 | for (;obj != null; obj = Object.getPrototypeOf(obj)) { 14 | let node = newNode(genHeader(obj)) 15 | node.nodes = Object.getOwnPropertyNames(obj) 16 | node.nodes.push(...Object.getOwnPropertySymbols(obj)) 17 | node = processNode(node, obj) 18 | tree = tree || node 19 | currentNode.nodes.push(node) 20 | currentNode = node 21 | } 22 | console.log(archy(tree)) 23 | } 24 | 25 | function processNode (node, obj) { 26 | for (let i = 0; i < node.nodes.length; i++) { 27 | let focusObj = null 28 | let propertyIsGetter = false 29 | let type 30 | try { 31 | propertyIsGetter = isGetter(obj, node.nodes[i]) 32 | focusObj = obj[node.nodes[i]] 33 | type = getTypeString(focusObj) 34 | } catch (err) { 35 | type = propertyIsGetter ? types.Getter : types.Unknown 36 | focusObj = err 37 | } 38 | node.nodes[i] = getNodeString(type, focusObj, node.nodes[i]) 39 | } 40 | node.nodes.sort((a, b) => { 41 | return stripAnsi(a).localeCompare(stripAnsi(b)) 42 | }) 43 | return node 44 | } 45 | 46 | function getNodeString (type, obj, node) { 47 | let prefix = applyChalk(type, `[${type}]`) 48 | const postfix = genPostfix(type, obj) 49 | const isSymbolKey = getTypeString(node) === types.Symbol 50 | if (isSymbolKey) { 51 | const symDesc = getSymbolDescription(node) 52 | prefix = applyChalk(types.Symbol, `[${types.Symbol}]`) + prefix 53 | if (symDesc) { 54 | return `${prefix} ${symDesc} ${postfix}` 55 | } else { 56 | return `${prefix} ${postfix}` 57 | } 58 | } 59 | return `${prefix} ${node} ${postfix}` 60 | } 61 | 62 | function newNode (label) { 63 | return { 64 | label, 65 | nodes: [] 66 | } 67 | } 68 | 69 | function genHeader (obj) { 70 | const constName = obj.constructor.name ? obj.constructor.name : '' 71 | let objName = isGetter(obj, 'name') ? applyChalk(types.Getter, `[${types.Getter}] name ()`) : '' 72 | try { objName = obj.name && obj.name } catch (err) { } 73 | const objSignature = genSignature(obj) 74 | let header = constName ? `[${constName}]` : `[${typeof obj}]` 75 | header = chalk.red(header) 76 | header += objName ? ` ${objName}` : '' 77 | header += objSignature ? ` ${objSignature}` : '' 78 | return header 79 | } 80 | 81 | function isGetter (obj, propertyName) { 82 | const descriptor = Object.getOwnPropertyDescriptor(obj, propertyName) 83 | return !!(descriptor && descriptor.get && typeof descriptor.get === 'function') 84 | } 85 | 86 | function getTypeString (obj) { 87 | if (Number.isNaN(obj)) return types.NaN 88 | return Object.prototype.toString.call(obj).slice(8, -1) 89 | } 90 | 91 | function genPostfix (type, obj) { 92 | let postfix = '' 93 | let symDesc = '' 94 | switch (type) { 95 | case types.Infinity: 96 | case types.NaN: 97 | case types.Undefined: 98 | case types.Null: 99 | break 100 | case types.Object: 101 | postfix = applyChalk(type, `[keys: ${Object.getOwnPropertyNames(obj).length}]`) 102 | break 103 | case types.Function: 104 | case types.GeneratorFunction: 105 | case types.AsyncFunction: 106 | postfix = applyChalk(type, genSignature(obj)) 107 | break 108 | case types.Boolean: 109 | postfix = applyChalk(type, `[${obj.toString()}]`) 110 | break 111 | case types.Symbol: 112 | symDesc = getSymbolDescription(obj) 113 | if (symDesc) { 114 | postfix = applyChalk(type, `[desc: ${symDesc}]`) 115 | } 116 | break 117 | case types.Error: 118 | postfix = obj.message && applyChalk(type, `[${cleanString(obj.message)}]`) 119 | break 120 | case types.Number: 121 | case types.BigInt: 122 | postfix = applyChalk(type, `[${obj.toString()}]`) 123 | break 124 | case types.Date: 125 | postfix = applyChalk(type, `[${obj.toString()}]`) 126 | break 127 | case types.String: 128 | postfix = applyChalk(type, `[${cleanString(obj)}]`) 129 | break 130 | case types.RegExp: 131 | postfix = applyChalk(type, `[${limitString(obj.toString())}]`) 132 | break 133 | case types.Array: 134 | case types.Int8Array: 135 | case types.Uint8Array: 136 | case types.Uint8ClampedArray: 137 | case types.Int16Array: 138 | case types.Uint16Array: 139 | case types.Int32Array: 140 | case types.Uint32Array: 141 | case types.Float32Array: 142 | case types.Float64Array: 143 | postfix = applyChalk(type, `[len: ${obj.length}]`) 144 | break 145 | case types.Map: 146 | case types.Set: 147 | postfix = applyChalk(type, `[size: ${obj.size}]`) 148 | break 149 | case types.ArrayBuffer: 150 | case types.SharedArrayBuffer: 151 | case types.DataView: 152 | postfix = applyChalk(type, `[len: ${obj.byteLength}]`) 153 | break 154 | default: 155 | break 156 | } 157 | return postfix 158 | } 159 | 160 | function cleanString (value) { 161 | const str = value.replace(/(?:\r\n|\r|\n)/g, '') 162 | return limitString(str) 163 | } 164 | 165 | function limitString (value) { 166 | const limit = 15 167 | return value.length > limit ? value.substring(0, limit) + '...' : value 168 | } 169 | 170 | function getSymbolDescription (sym) { 171 | return String(sym).slice(7, -1) 172 | } 173 | 174 | function applyChalk (type, str) { 175 | let result 176 | switch (type) { 177 | // Null Types 178 | case types.Infinity: 179 | case types.NaN: 180 | case types.Undefined: 181 | case types.Null: 182 | result = str // No colour 183 | break 184 | // Objects and Properties 185 | case types.Object: 186 | case types.Symbol: 187 | case types.Date: 188 | result = chalk.yellow(str) 189 | break 190 | // Collections and Arrays 191 | case types.Array: 192 | case types.Int8Array: 193 | case types.Uint8Array: 194 | case types.Uint8ClampedArray: 195 | case types.Int16Array: 196 | case types.Uint16Array: 197 | case types.Int32Array: 198 | case types.Uint32Array: 199 | case types.Float32Array: 200 | case types.Float64Array: 201 | case types.Map: 202 | case types.Set: 203 | case types.WeakMap: 204 | case types.WeakSet: 205 | result = chalk.blue(str) 206 | break 207 | // Structured Data and Boolean 208 | case types.Boolean: 209 | case types.ArrayBuffer: 210 | case types.SharedArrayBuffer: 211 | case types.Atomics: 212 | case types.DataView: 213 | result = chalk.cyan(str) 214 | break 215 | // Functions and Control Objects 216 | case types.Getter: 217 | case types.Function: 218 | case types.Promise: 219 | case types.Generator: 220 | case types.GeneratorFunction: 221 | case types.AsyncFunction: 222 | result = chalk.green(str) 223 | break 224 | // Number Types 225 | case types.Number: 226 | case types.BigInt: 227 | result = chalk.blue(str) 228 | break 229 | // Strings 230 | case types.String: 231 | case types.RegExp: 232 | result = chalk.magenta(str) 233 | break 234 | // Errors 235 | case types.Error: 236 | result = chalk.red(str) 237 | break 238 | default: 239 | result = str 240 | break 241 | } 242 | return result 243 | } 244 | 245 | function genSignature (obj) { 246 | let funString = '' 247 | if (!isFunction(obj)) { return funString } 248 | try { 249 | funString = Function.prototype.toString.call(obj) 250 | funString = funString.slice(funString.indexOf('('), funString.indexOf(')') + 1) 251 | } catch (err) { } 252 | return funString.slice(funString.indexOf('('), funString.indexOf(')') + 1) 253 | } 254 | 255 | function isFunction (obj) { 256 | const type = getTypeString(obj) 257 | return type === types.Function || type === types.GeneratorFunction || type === types.AsyncFunction 258 | } 259 | -------------------------------------------------------------------------------- /src/console-yaml.js: -------------------------------------------------------------------------------- 1 | const prettyJson = require('prettyjson') 2 | const valid = require('./valid') 3 | 4 | module.exports = function yaml (obj, options, indentation) { 5 | if (!valid(obj)) { return } 6 | console.log(prettyJson.render(obj, options, indentation)) 7 | } 8 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const probe = require('./console-probe') 2 | const json = require('./console-json') 3 | const yaml = require('./console-yaml') 4 | const ls = require('./console-ls') 5 | 6 | module.exports = Object.freeze({ 7 | apply, 8 | probe, 9 | json, 10 | yaml, 11 | ls 12 | }) 13 | 14 | function apply (obj) { 15 | if (obj == null) { 16 | global.console.probe = probe 17 | global.console.json = json 18 | global.console.yaml = yaml 19 | global.console.ls = ls 20 | } else { 21 | obj.probe = probe 22 | obj.json = json 23 | obj.yaml = yaml 24 | obj.ls = ls 25 | } 26 | } 27 | 28 | // Adding BigInt support for JSON.stringify() 29 | if (global.BigInt) { 30 | global.BigInt.prototype.toJSON = function (key) { 31 | return this.toString() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | module.exports = Object.freeze({ 2 | // Type Errors 3 | Unknown: 'Unknown', 4 | Getter: 'Getter', 5 | 6 | // Value Properties 7 | Infinity: 'Infinity', 8 | NaN: 'NaN', 9 | Undefined: 'Undefined', 10 | Null: 'Null', 11 | 12 | // Fundamental Objects 13 | Object: 'Object', 14 | Function: 'Function', 15 | Boolean: 'Boolean', 16 | Symbol: 'Symbol', 17 | Error: 'Error', 18 | 19 | // Numbers and Dates 20 | Number: 'Number', 21 | BigInt: 'BigInt', 22 | Date: 'Date', 23 | 24 | // Text Processing 25 | String: 'String', 26 | RegExp: 'RegExp', 27 | 28 | // Indexed Collections 29 | Array: 'Array', 30 | Int8Array: 'Int8Array', 31 | Uint8Array: 'Uint8Array', 32 | Uint8ClampedArray: 'Uint8ClampedArray', 33 | Int16Array: 'Int16Array', 34 | Uint16Array: 'Uint16Array', 35 | Int32Array: 'Int32Array', 36 | Uint32Array: 'Uint32Array', 37 | Float32Array: 'Float32Array', 38 | Float64Array: 'Float64Array', 39 | 40 | // Keyed Collections 41 | Map: 'Map', 42 | Set: 'Set', 43 | WeakMap: 'WeakMap', 44 | WeakSet: 'WeakSet', 45 | 46 | // Structured Data 47 | ArrayBuffer: 'ArrayBuffer', 48 | SharedArrayBuffer: 'SharedArrayBuffer', 49 | Atomics: 'Atomics', 50 | DataView: 'DataView', 51 | 52 | // Control Abstraction Objects 53 | Promise: 'Promise', 54 | Generator: 'Generator', 55 | GeneratorFunction: 'GeneratorFunction', 56 | AsyncFunction: 'AsyncFunction' 57 | }) 58 | -------------------------------------------------------------------------------- /src/valid.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | 3 | module.exports = function valid (value) { 4 | if (value == null) { 5 | let message = chalk.red('[console-probe] Cannot inspect: ') 6 | message += Object.prototype.toString.call(value) 7 | console.log(message) 8 | return false 9 | } 10 | return true 11 | } 12 | -------------------------------------------------------------------------------- /tests/console-probe.test.js: -------------------------------------------------------------------------------- 1 | const cp = require('../index') 2 | const arrLen = 2 3 | const SharedArrayBuffer = global.SharedArrayBuffer ? global.SharedArrayBuffer : function () {} 4 | const Atomics = global.Atomics ? global.Atomics : Promise.resolve() 5 | const BigInt = global.BigInt ? global.BigInt : function () {} 6 | 7 | const aussieSlang = { 8 | name: 'Aussie Slang Words', 9 | gday: Infinity, 10 | maccas: Number.NaN, 11 | yobbo: BigInt(123), 12 | arvo: undefined, 13 | straya: null, 14 | footy: { specky: true }, 15 | biccy: (size, toppings) => {}, 16 | servo: true, 17 | choccy: Symbol('Mmmmm...'), 18 | 'bottle-o': Error('Cheers mate! My shout next'), 19 | tinny: 42, 20 | coppa: new Date(), 21 | tradie: 'She\'ll be right mate?', 22 | postie: /a.long.regexp.that.keeps.giving/, 23 | garbo: [1, 2, 3], 24 | muso: new Int8Array(arrLen), 25 | cabbie: new Uint8Array(arrLen), 26 | ambo: new Uint8ClampedArray(arrLen), 27 | prezzie: new Int16Array(arrLen), 28 | chrissie: new Uint16Array(arrLen), 29 | cuppa: new Int32Array(arrLen), 30 | mate: new Uint32Array(arrLen), 31 | snag: new Float32Array(arrLen), 32 | drongo: new Float64Array(arrLen), 33 | fairDinkum: new Map([['foo', 'bar']]), 34 | bonza: new Set([['foo', 'bar']]), 35 | tooRight: new WeakMap(), 36 | dunny: new WeakSet(), 37 | cobber: new ArrayBuffer(arrLen), 38 | barbie: new SharedArrayBuffer(arrLen), 39 | stickybeak: Atomics, 40 | stoked: new DataView(new ArrayBuffer(arrLen)), 41 | ripper: Promise.resolve(), 42 | mongrel: (function * () {})(), 43 | holyDooley: function * (foo, bar) {}, 44 | roo: async function (foo, bar) {} 45 | } 46 | const secret = Symbol('Hidden Property') 47 | aussieSlang[secret] = 'Bogan' 48 | 49 | describe('suppressed log tests', () => { 50 | const spyLog = jest.fn() 51 | const consoleLog = console.log 52 | 53 | beforeAll(() => { 54 | console.log = spyLog 55 | }) 56 | 57 | test('console-probe functions called by console object', () => { 58 | expect(() => console.probe()).toThrow() 59 | expect(() => console.json()).toThrow() 60 | expect(() => console.yaml()).toThrow() 61 | cp.apply() 62 | console.probe() 63 | expect(spyLog).toHaveBeenCalledTimes(1) 64 | console.probe(undefined) 65 | expect(spyLog).toHaveBeenCalledTimes(2) 66 | console.probe(null) 67 | expect(spyLog).toHaveBeenCalledTimes(3) 68 | console.probe(aussieSlang) 69 | expect(spyLog).toHaveBeenCalledTimes(4) 70 | console.json() 71 | expect(spyLog).toHaveBeenCalledTimes(5) 72 | console.json(undefined) 73 | expect(spyLog).toHaveBeenCalledTimes(6) 74 | console.json(null) 75 | expect(spyLog).toHaveBeenCalledTimes(7) 76 | console.json(aussieSlang) 77 | expect(spyLog).toHaveBeenCalledTimes(8) 78 | console.yaml() 79 | expect(spyLog).toHaveBeenCalledTimes(9) 80 | console.yaml(undefined) 81 | expect(spyLog).toHaveBeenCalledTimes(10) 82 | console.yaml(null) 83 | expect(spyLog).toHaveBeenCalledTimes(11) 84 | console.yaml(aussieSlang) 85 | expect(spyLog).toHaveBeenCalledTimes(12) 86 | console.ls() 87 | expect(spyLog).toHaveBeenCalledTimes(13) 88 | console.ls(undefined) 89 | expect(spyLog).toHaveBeenCalledTimes(14) 90 | console.ls(null) 91 | expect(spyLog).toHaveBeenCalledTimes(15) 92 | console.ls(aussieSlang) 93 | expect(spyLog).toHaveBeenCalledTimes(16) 94 | }) 95 | 96 | test('console-probe functions appended to another object', () => { 97 | const thing = {} 98 | expect(() => thing.probe()).toThrow() 99 | expect(() => thing.json()).toThrow() 100 | expect(() => thing.yaml()).toThrow() 101 | cp.apply(thing) 102 | const probeSpy = jest.spyOn(thing, 'probe') 103 | thing.probe(aussieSlang) 104 | expect(probeSpy).toHaveBeenCalledTimes(1) 105 | const jsonSpy = jest.spyOn(thing, 'json') 106 | thing.json(aussieSlang) 107 | expect(jsonSpy).toHaveBeenCalledTimes(1) 108 | const yamlSpy = jest.spyOn(thing, 'yaml') 109 | thing.yaml(aussieSlang) 110 | expect(yamlSpy).toHaveBeenCalledTimes(1) 111 | const lsSpy = jest.spyOn(thing, 'ls') 112 | thing.ls(aussieSlang) 113 | expect(lsSpy).toHaveBeenCalledTimes(1) 114 | }) 115 | 116 | test('console-probe stand-alone functions', () => { 117 | expect(typeof cp.probe).toBe('function') 118 | expect(cp.probe).toBe(console.probe) 119 | expect(cp.probe.toString()).toBe(console.probe.toString()) 120 | expect(typeof cp.json).toBe('function') 121 | expect(cp.json).toBe(console.json) 122 | expect(cp.json.toString()).toBe(console.json.toString()) 123 | expect(typeof cp.yaml).toBe('function') 124 | expect(cp.yaml).toBe(console.yaml) 125 | expect(cp.yaml.toString()).toBe(console.yaml.toString()) 126 | expect(typeof cp.ls).toBe('function') 127 | expect(cp.ls).toBe(console.ls) 128 | expect(cp.ls.toString()).toBe(console.ls.toString()) 129 | }) 130 | 131 | test('console-probe type support', () => { 132 | expect(() => { cp.probe() }).not.toThrow() 133 | expect(() => { cp.probe(Infinity) }).not.toThrow() 134 | expect(() => { cp.probe(Number.NaN) }).not.toThrow() 135 | expect(() => { cp.probe(BigInt(0)) }).not.toThrow() 136 | expect(() => { cp.probe(undefined) }).not.toThrow() 137 | expect(() => { cp.probe(null) }).not.toThrow() 138 | expect(() => { cp.probe({}) }).not.toThrow() 139 | expect(() => { cp.probe(function name () {}) }).not.toThrow() 140 | expect(() => { cp.probe(() => {}) }).not.toThrow() 141 | expect(() => { cp.probe(true) }).not.toThrow() 142 | expect(() => { cp.probe(Symbol('test')) }).not.toThrow() 143 | expect(() => { cp.probe(new Error('test')) }).not.toThrow() 144 | expect(() => { cp.probe(1) }).not.toThrow() 145 | expect(() => { cp.probe(-1) }).not.toThrow() 146 | expect(() => { cp.probe(0) }).not.toThrow() 147 | expect(() => { cp.probe(new Date()) }).not.toThrow() 148 | expect(() => { cp.probe('') }).not.toThrow() 149 | expect(() => { cp.probe(/a/) }).not.toThrow() 150 | expect(() => { cp.probe([]) }).not.toThrow() 151 | expect(() => { cp.probe(new Int8Array()) }).not.toThrow() 152 | expect(() => { cp.probe(new Uint8Array()) }).not.toThrow() 153 | expect(() => { cp.probe(new Uint8ClampedArray()) }).not.toThrow() 154 | expect(() => { cp.probe(new Int16Array()) }).not.toThrow() 155 | expect(() => { cp.probe(new Uint16Array()) }).not.toThrow() 156 | expect(() => { cp.probe(new Int32Array()) }).not.toThrow() 157 | expect(() => { cp.probe(new Uint32Array()) }).not.toThrow() 158 | expect(() => { cp.probe(new Float32Array()) }).not.toThrow() 159 | expect(() => { cp.probe(new Float64Array()) }).not.toThrow() 160 | expect(() => { cp.probe(new Map()) }).not.toThrow() 161 | expect(() => { cp.probe(new Set()) }).not.toThrow() 162 | expect(() => { cp.probe(new WeakMap()) }).not.toThrow() 163 | expect(() => { cp.probe(new WeakSet()) }).not.toThrow() 164 | expect(() => { cp.probe(new ArrayBuffer()) }).not.toThrow() 165 | expect(() => { cp.probe(new SharedArrayBuffer()) }).not.toThrow() 166 | expect(() => { cp.probe(Atomics) }).not.toThrow() 167 | expect(() => { cp.probe(new DataView(new ArrayBuffer())) }).not.toThrow() 168 | expect(() => { cp.probe(Promise.resolve()) }).not.toThrow() 169 | expect(() => { cp.probe((function * () {})()) }).not.toThrow() 170 | expect(() => { cp.probe(function * () {}) }).not.toThrow() 171 | expect(() => { cp.probe(async function () {}) }).not.toThrow() 172 | expect(() => { cp.probe(cp) }).not.toThrow() 173 | expect(spyLog).toHaveBeenCalledTimes(61) 174 | }) 175 | 176 | test('console-probe class symbol getter support', () => { 177 | const _state = Symbol('state') 178 | class Thing { 179 | constructor () { this[_state] = { name: 'foo', tag: 'bar' } } 180 | get name () { return this[_state].name } 181 | get tag () { return this[_state].tag } 182 | } 183 | const thing = new Thing() 184 | expect(() => { cp.probe(thing) }).not.toThrow() 185 | }) 186 | 187 | afterAll(() => { 188 | console.log = consoleLog 189 | }) 190 | }) 191 | 192 | afterAll(() => { 193 | console.log() 194 | // cp.ls(aussieSlang) doesn't work well under jest 195 | cp.yaml(aussieSlang) 196 | cp.json(aussieSlang) 197 | cp.probe(aussieSlang) 198 | console.log() 199 | }) 200 | --------------------------------------------------------------------------------