├── .gitignore ├── art ├── banner.png └── banner.svg ├── fixture ├── basic.json └── bootstrap.json ├── license ├── package.json ├── readme.md └── src ├── cli.js ├── index.html ├── index.js └── renderer.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /art/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/queckezz/inspect-json/02ffbc2173e954ee766bc75ea2dcf76c5df9fb5b/art/banner.png -------------------------------------------------------------------------------- /art/banner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 25 | 28 | 32 | 36 | 37 | 47 | 48 | 68 | 70 | 71 | 73 | image/svg+xml 74 | 76 | 77 | 78 | 79 | 80 | 85 | 986 | 994 | 997 | inspect-json 1009 | 1012 | 1014 | 1021 | 1022 | 1025 | 1027 | 1034 | 1035 | 1037 | 1040 | 1044 | 1048 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1065 | 1066 | 1067 | -------------------------------------------------------------------------------- /fixture/basic.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "name": "Leanne Graham", 4 | "username": "Bret", 5 | "email": "Sincere@april.biz", 6 | "address": { 7 | "street": "Kulas Light", 8 | "suite": "Apt. 556", 9 | "city": "Gwenborough", 10 | "zipcode": "92998-3874", 11 | "geo": { 12 | "lat": "-37.3159", 13 | "lng": "81.1496" 14 | } 15 | }, 16 | "phone": "1-770-736-8031 x56442", 17 | "website": "hildegard.org", 18 | "company": { 19 | "name": "Romaguera-Crona", 20 | "catchPhrase": "Multi-layered client-server neural-net", 21 | "bs": "harness real-time e-markets" 22 | } 23 | } -------------------------------------------------------------------------------- /fixture/bootstrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2126244, 3 | "name": "bootstrap", 4 | "full_name": "twbs/bootstrap", 5 | "owner": { 6 | "login": "twbs", 7 | "id": 2918581, 8 | "avatar_url": "https://avatars.githubusercontent.com/u/2918581?v=3", 9 | "gravatar_id": "", 10 | "url": "https://api.github.com/users/twbs", 11 | "html_url": "https://github.com/twbs", 12 | "followers_url": "https://api.github.com/users/twbs/followers", 13 | "following_url": "https://api.github.com/users/twbs/following{/other_user}", 14 | "gists_url": "https://api.github.com/users/twbs/gists{/gist_id}", 15 | "starred_url": "https://api.github.com/users/twbs/starred{/owner}{/repo}", 16 | "subscriptions_url": "https://api.github.com/users/twbs/subscriptions", 17 | "organizations_url": "https://api.github.com/users/twbs/orgs", 18 | "repos_url": "https://api.github.com/users/twbs/repos", 19 | "events_url": "https://api.github.com/users/twbs/events{/privacy}", 20 | "received_events_url": "https://api.github.com/users/twbs/received_events", 21 | "type": "Organization", 22 | "site_admin": false 23 | }, 24 | "private": false, 25 | "html_url": "https://github.com/twbs/bootstrap", 26 | "description": "The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.", 27 | "fork": false, 28 | "url": "https://api.github.com/repos/twbs/bootstrap", 29 | "forks_url": "https://api.github.com/repos/twbs/bootstrap/forks", 30 | "keys_url": "https://api.github.com/repos/twbs/bootstrap/keys{/key_id}", 31 | "collaborators_url": "https://api.github.com/repos/twbs/bootstrap/collaborators{/collaborator}", 32 | "teams_url": "https://api.github.com/repos/twbs/bootstrap/teams", 33 | "hooks_url": "https://api.github.com/repos/twbs/bootstrap/hooks", 34 | "issue_events_url": "https://api.github.com/repos/twbs/bootstrap/issues/events{/number}", 35 | "events_url": "https://api.github.com/repos/twbs/bootstrap/events", 36 | "assignees_url": "https://api.github.com/repos/twbs/bootstrap/assignees{/user}", 37 | "branches_url": "https://api.github.com/repos/twbs/bootstrap/branches{/branch}", 38 | "tags_url": "https://api.github.com/repos/twbs/bootstrap/tags", 39 | "blobs_url": "https://api.github.com/repos/twbs/bootstrap/git/blobs{/sha}", 40 | "git_tags_url": "https://api.github.com/repos/twbs/bootstrap/git/tags{/sha}", 41 | "git_refs_url": "https://api.github.com/repos/twbs/bootstrap/git/refs{/sha}", 42 | "trees_url": "https://api.github.com/repos/twbs/bootstrap/git/trees{/sha}", 43 | "statuses_url": "https://api.github.com/repos/twbs/bootstrap/statuses/{sha}", 44 | "languages_url": "https://api.github.com/repos/twbs/bootstrap/languages", 45 | "stargazers_url": "https://api.github.com/repos/twbs/bootstrap/stargazers", 46 | "contributors_url": "https://api.github.com/repos/twbs/bootstrap/contributors", 47 | "subscribers_url": "https://api.github.com/repos/twbs/bootstrap/subscribers", 48 | "subscription_url": "https://api.github.com/repos/twbs/bootstrap/subscription", 49 | "commits_url": "https://api.github.com/repos/twbs/bootstrap/commits{/sha}", 50 | "git_commits_url": "https://api.github.com/repos/twbs/bootstrap/git/commits{/sha}", 51 | "comments_url": "https://api.github.com/repos/twbs/bootstrap/comments{/number}", 52 | "issue_comment_url": "https://api.github.com/repos/twbs/bootstrap/issues/comments{/number}", 53 | "contents_url": "https://api.github.com/repos/twbs/bootstrap/contents/{+path}", 54 | "compare_url": "https://api.github.com/repos/twbs/bootstrap/compare/{base}...{head}", 55 | "merges_url": "https://api.github.com/repos/twbs/bootstrap/merges", 56 | "archive_url": "https://api.github.com/repos/twbs/bootstrap/{archive_format}{/ref}", 57 | "downloads_url": "https://api.github.com/repos/twbs/bootstrap/downloads", 58 | "issues_url": "https://api.github.com/repos/twbs/bootstrap/issues{/number}", 59 | "pulls_url": "https://api.github.com/repos/twbs/bootstrap/pulls{/number}", 60 | "milestones_url": "https://api.github.com/repos/twbs/bootstrap/milestones{/number}", 61 | "notifications_url": "https://api.github.com/repos/twbs/bootstrap/notifications{?since,all,participating}", 62 | "labels_url": "https://api.github.com/repos/twbs/bootstrap/labels{/name}", 63 | "releases_url": "https://api.github.com/repos/twbs/bootstrap/releases{/id}", 64 | "deployments_url": "https://api.github.com/repos/twbs/bootstrap/deployments", 65 | "created_at": "2011-07-29T21:19:00Z", 66 | "updated_at": "2016-11-24T15:58:44Z", 67 | "pushed_at": "2016-11-24T02:24:54Z", 68 | "git_url": "git://github.com/twbs/bootstrap.git", 69 | "ssh_url": "git@github.com:twbs/bootstrap.git", 70 | "clone_url": "https://github.com/twbs/bootstrap.git", 71 | "svn_url": "https://github.com/twbs/bootstrap", 72 | "homepage": "http://getbootstrap.com", 73 | "size": 215143, 74 | "stargazers_count": 103838, 75 | "watchers_count": 103838, 76 | "language": "JavaScript", 77 | "has_issues": true, 78 | "has_downloads": true, 79 | "has_wiki": false, 80 | "has_pages": true, 81 | "forks_count": 46970, 82 | "mirror_url": null, 83 | "open_issues_count": 402, 84 | "forks": 46970, 85 | "open_issues": 402, 86 | "watchers": 103838, 87 | "default_branch": "v4-dev", 88 | "organization": { 89 | "login": "twbs", 90 | "id": 2918581, 91 | "avatar_url": "https://avatars.githubusercontent.com/u/2918581?v=3", 92 | "gravatar_id": "", 93 | "url": "https://api.github.com/users/twbs", 94 | "html_url": "https://github.com/twbs", 95 | "followers_url": "https://api.github.com/users/twbs/followers", 96 | "following_url": "https://api.github.com/users/twbs/following{/other_user}", 97 | "gists_url": "https://api.github.com/users/twbs/gists{/gist_id}", 98 | "starred_url": "https://api.github.com/users/twbs/starred{/owner}{/repo}", 99 | "subscriptions_url": "https://api.github.com/users/twbs/subscriptions", 100 | "organizations_url": "https://api.github.com/users/twbs/orgs", 101 | "repos_url": "https://api.github.com/users/twbs/repos", 102 | "events_url": "https://api.github.com/users/twbs/events{/privacy}", 103 | "received_events_url": "https://api.github.com/users/twbs/received_events", 104 | "type": "Organization", 105 | "site_admin": false 106 | }, 107 | "network_count": 46970, 108 | "subscribers_count": 6602 109 | } 110 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2016 Fabian Eichenberger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inspect-json", 3 | "version": "0.2.0", 4 | "description": "Robust manipulation and inspection of JSON data using the already familiar Chromium Devtools", 5 | "main": "src/index.js", 6 | "bin": "src/cli.js", 7 | "scripts": { 8 | "start": "electron ." 9 | }, 10 | "repository": "https://github.com/queckezz/electron-json-viewer", 11 | "author": "Fabian Eichenberger ", 12 | "license": "MIT", 13 | "devDependencies": {}, 14 | "dependencies": { 15 | "chokidar": "^1.6.1", 16 | "electron": "^1.4.8", 17 | "execa": "^0.5.0", 18 | "get-stdin": "^5.0.1", 19 | "got": "^6.6.3", 20 | "is-url": "^1.2.2", 21 | "minimist": "^1.2.0", 22 | "mz": "^2.6.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | ![./banner](art/banner.png) 3 | 4 | **Robust manipulation and inspection of JSON data using the already familiar Chromium Devtools** - It allows for *quick* inspection of arbitrary JSON strucures. Allows JSON to be passed in from **URLs**, **Files** and **`process.stdin`**. The JSON can be manipulated while inspecting by accessing `window.json` through the console. 5 | 6 | 7 | 8 | [![npm version][version-image]][version-url] 9 | [![dependency status][david-image]][david-url] 10 | [![license][license-image]][license-url] 11 | [![js standard style][standard-image]][standard-url] 12 | [![downloads per month][downloads-image]][downloads-url] 13 | 14 | ## Installation 15 | 16 | ``` 17 | > npm install -g inspect-json 18 | ``` 19 | 20 | ## Examples 21 | 22 | Inspect JSON from the following types. 23 | 24 | **File:** 25 | 26 | ``` 27 | > inspect-json example.json 28 | ``` 29 | 30 | **REST Endpoint:** 31 | 32 | ``` 33 | > inspect-json https://api.github.com/users/mbostock 34 | ``` 35 | 36 | **Standard Input (CLI):** 37 | 38 | ``` 39 | > echo { "test": true } | inspect-json 40 | ``` 41 | 42 | **Inspecting webpack output stats:** 43 | 44 | Let's say you have a webpack stats object that you want to analyse. How would you go about doing that? Just pipe it into `inspect-json` 45 | 46 | ``` 47 | > webpack --stats | inspect-json 48 | ``` 49 | 50 | 51 | 52 | ## License 53 | 54 | [MIT][license-url] 55 | 56 | [version-image]: https://img.shields.io/npm/v/inspect-json.svg?style=flat-square 57 | [version-url]: https://npmjs.org/package/inspect-json 58 | 59 | [downloads-image]: https://img.shields.io/npm/dm/inspect-json.svg?style=flat-square 60 | [downloads-url]: https://npmjs.org/package/inspect-json 61 | 62 | [david-image]: http://img.shields.io/david/queckezz/inspect-json.svg?style=flat-square 63 | [david-url]: https://david-dm.org/queckezz/inspect-json 64 | 65 | [standard-image]: https://img.shields.io/badge/code-standard-brightgreen.svg?style=flat-square 66 | [standard-url]: https://github.com/feross/standard 67 | 68 | [license-image]: http://img.shields.io/npm/l/inspect-json.svg?style=flat-square 69 | [license-url]: ./license -------------------------------------------------------------------------------- /src/cli.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | const { readFileSync } = require('fs') 3 | const getStdin = require('get-stdin') 4 | const minimist = require('minimist') 5 | const { join } = require('path') 6 | const execa = require('execa') 7 | 8 | const help = () => ` 9 | Usage: 10 | inspect-json [file|url] 11 | 12 | Examples: 13 | https://github.com/queckezz/inspect-json#examples 14 | ` 15 | 16 | const mainProcess = join(__dirname, 'index.js') 17 | 18 | const args = minimist(process.argv.slice(2), { 19 | alias: { h: 'help', v: 'version' } 20 | }) 21 | 22 | if (args.help) return console.log(help()) 23 | 24 | if (args.version) { 25 | const contents = readFileSync(join(__dirname, '../package.json'), 'utf-8') 26 | return console.log(JSON.parse(contents).version) 27 | } 28 | 29 | const source = args._[0] 30 | 31 | if (!source) { 32 | getStdin().then((str) => { 33 | if (str.length == 0) { 34 | return console.log(help()) 35 | } 36 | try { 37 | const json = JSON.parse(str) 38 | execa('electron', [mainProcess, JSON.stringify(json)]) 39 | } catch (e) { 40 | console.error(e) 41 | } 42 | }) 43 | } else { 44 | execa('electron', [mainProcess, source]) 45 | } 46 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron JSON Viewer 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | const { BrowserWindow, app } = require('electron') 3 | const { ipcMain } = require('electron') 4 | const { readFile } = require('mz/fs') 5 | const { watch } = require('chokidar') 6 | const minimist = require('minimist') 7 | const { resolve } = require('path') 8 | const isUrl = require('is-url') 9 | const got = require('got') 10 | 11 | const argv = minimist(process.argv.slice(2)) 12 | let win = null 13 | 14 | const emitFromFile = (source, renderer) => { 15 | return readFile(source) 16 | .then(JSON.parse) 17 | .then((json) => { 18 | renderer.send('json', { file: true, source, json }) 19 | }) 20 | .catch((error) => { 21 | renderer.send('error', { file: true, source, error }) 22 | }) 23 | } 24 | 25 | const emitFromHttp = (source, renderer) => { 26 | return got(source, { json: true }) 27 | .then((res) => res.body) 28 | .then((json) => { 29 | renderer.send('json', { source, json }) 30 | }) 31 | .catch((error) => { 32 | renderer.send('error', { source, error }) 33 | }) 34 | } 35 | 36 | app.on('ready', () => { 37 | const source = argv._[0] 38 | 39 | win = new BrowserWindow({ 40 | useContentSize: true, 41 | width: 0, 42 | height: 0, 43 | x: 0, 44 | y: 0 45 | }) 46 | 47 | const renderer = win.webContents 48 | 49 | win.loadURL(`file://${__dirname}/index.html`) 50 | 51 | win.on('closed', () => { 52 | win = null 53 | }) 54 | 55 | renderer.on('did-finish-load', () => { 56 | try { 57 | const json = JSON.parse(source) 58 | renderer.send('json', { source: 'stdin', json }) 59 | } catch (e) { 60 | if (isUrl(source)) { 61 | emitFromHttp(source, renderer) 62 | } else { 63 | const fileSource = resolve(process.cwd(), source) 64 | const watcher = watch(fileSource) 65 | 66 | watcher.on('change', () => { 67 | emitFromFile(fileSource, renderer) 68 | }) 69 | 70 | emitFromFile(fileSource, renderer) 71 | } 72 | } 73 | }) 74 | 75 | renderer.once('devtools-opened', (t) => { 76 | win.hide() 77 | }) 78 | 79 | renderer.once('devtools-closed', (t) => { 80 | setImmediate(app.exit) 81 | }) 82 | 83 | renderer.openDevTools({ mode: 'undocked' }) 84 | }) -------------------------------------------------------------------------------- /src/renderer.js: -------------------------------------------------------------------------------- 1 | 2 | const { ipcRenderer } = require('electron') 3 | 4 | const pad = (str = '') => ' ' + str 5 | 6 | const render = ({ file, source, json, error }) => { 7 | if (window.json || error) { 8 | console.clear() 9 | } 10 | 11 | if (file) { 12 | console.log('%c✔ Reloads on changes', 'color: #94d82d;') 13 | } 14 | 15 | console.log( 16 | `%cInspecting %c${source}`, 17 | 'font-weight: normal; background: #f1f3f5; color: #91a7ff', 18 | 'font-weight: bold; background: #f1f3f5; color: #91a7ff' 19 | ) 20 | 21 | console.log( 22 | pad('%c(Also accessible through %cwindow.json)'), 23 | 'color: #adb5bd;', 24 | 'color: #adb5bd; font-weight: bold;' 25 | ) 26 | 27 | if (error) { 28 | console.error(error) 29 | } else { 30 | console.log(pad(), json) 31 | } 32 | } 33 | 34 | ipcRenderer.on('json', (event, data) => { 35 | render(data) 36 | window.json = data.json 37 | }) 38 | 39 | ipcRenderer.on('error', (event, data) => { 40 | render(data) 41 | }) 42 | --------------------------------------------------------------------------------