├── .github └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── index.mjs ├── package-lock.json ├── package.json ├── test.html ├── test.js └── usage.js /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '37 20 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'javascript' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v1 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test.js 2 | test.html 3 | .github 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yaniv Kessler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-bcat 2 | Pipe to the browser utility, Very useful for log tail fun :) 3 | 4 | node-bcat features auto scrolling (with enable/disable), ansi to html coloring (--ansi) and behavior and color customization. 5 | 6 | This module uses [RC](https://github.com/dominictarr/rc) to manage its configuration, so in addition to command line arguments you may save your favorite configuration in .bcatrc. 7 | 8 | ## example 9 | ``` 10 | > npm install -g bcat 11 | 12 | > cat somefile | bcat 13 | 14 | // redirect error stream also 15 | > node index.js 2>&1 | bcat 16 | ``` 17 | Want to see something moving too? 18 | 19 | test.js: 20 | ```js 21 | setInterval(function () { 22 | console.log(1) 23 | }, 1000) 24 | ``` 25 | then 26 | ``` 27 | > node test.js | bcat 28 | ``` 29 | ![screenshot](https://raw.github.com/kessler/static/master/node-bcat.png) 30 | 31 | ## usage 32 | ``` 33 | --port set a port for this bcat execution 34 | --contentType content type header, must be lower case [default: "text/html"] 35 | --backgroundColor (only in text/html) [default: "#000000"] 36 | --foregroundColor (only in text/html) [default: "#ffffff"] 37 | --tabLength length of a tab in spaces [default: 4] 38 | --tabReplace tab replacement [default: "    " 39 | --disableTabReplace disable tab replacement [default: false] 40 | --newlineReplace new line replacement [default: "
" 41 | --disableNewlineReplace disable new line replacement [default: false] 42 | --ansi show colorful ansi (implies text/html) [default: true] 43 | --ansiOptions override replacement of ansi black color 44 | --scrollDownInterval interval to execute javascript scroll down [default: 1000 (ms)] 45 | --serverTimeout http://nodejs.org/api/http.html#http_server_timeout [default: 0 (no timeout)] 46 | ``` 47 | - _An available port between 8080 - 8181 will be automatically picked if --port is not specified_ 48 | - _ansi feature is on by default_ 49 | 50 | ![be a good cat](https://raw.github.com/kessler/static/master/bcat.jpg) 51 | 52 | ## older version 53 | 54 | Since 3.0.0 the code base was updated and all dependencies too. The older version is at `bcat@2.0.0` 55 | 56 | ## related 57 | [catchart](https://github.com/kessler/catchart) - pipe data into charts in your browser 58 | 59 | [scat](https://github.com/hughsk/scat) - pipes javascript into your browser 60 | 61 | [hcat](https://github.com/kessler/node-hcat) - pipes html into your browser 62 | 63 | [bpipe](https://github.com/Marak/bpipe) - bidirectional piping between unix and the browser 64 | 65 | [browser-run](https://github.com/juliangruber/browser-run) - The easiest way of running code in a browser environment 66 | 67 | Inspired by a ruby [bcat](https://github.com/rtomayko/bcat) implementation 68 | -------------------------------------------------------------------------------- /index.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import open from 'open'; 4 | import isos from 'isos'; 5 | import http from 'http'; 6 | import { spawn } from 'child_process'; 7 | import ansi from '@kessler/ansi-html-stream'; 8 | import replaceStream from 'replacestream'; 9 | import os from 'os'; 10 | import rc from 'rc'; 11 | 12 | const config = rc('bcat', { 13 | port: 0, 14 | contentType: 'text/html', 15 | scrollDownInterval: 1000, 16 | backgroundColor: '#333', 17 | foregroundColor: '#fefefe', 18 | tabLength: 4, 19 | tabReplace: '    ', 20 | disableTabReplace: false, 21 | newlineReplace: '
', 22 | disableNewlineReplace: false, 23 | ansi: true, 24 | ansiOptions: { 25 | foregrounds: { 26 | '30': { style: 'color:#fffaaa' }, 27 | }, 28 | backgrounds: { 29 | '40': { style: 'background-color:#fffaaa' }, 30 | } 31 | }, 32 | serverTimeout: 0, 33 | command: undefined 34 | }); 35 | 36 | if (config.usage || config.help) { 37 | console.log(await import('./usage.js')); 38 | process.exit(0); 39 | } 40 | 41 | cat(config.port); 42 | 43 | const clientConfig = { 44 | scrollDownInterval: config.scrollDownInterval 45 | }; 46 | 47 | function run() { 48 | let ref; 49 | 50 | const startAutoScroll = () => { 51 | ref = setInterval(() => { 52 | document.getElementById('container').scrollIntoView(false); 53 | }, clientConfig.scrollDownInterval); 54 | }; 55 | 56 | const stopAutoScroll = () => { 57 | clearInterval(ref); 58 | }; 59 | 60 | const scrollToggle = document.getElementById('autoscrollToggle'); 61 | if (scrollToggle) { 62 | scrollToggle.addEventListener('change', () => { 63 | scrollToggle.checked ? startAutoScroll() : stopAutoScroll(); 64 | }); 65 | } 66 | 67 | startAutoScroll(); 68 | } 69 | 70 | const script = `var clientConfig = ${JSON.stringify(clientConfig)};\n${run.toString()}\nrun();`; 71 | 72 | function cat(port) { 73 | const server = http.createServer(handler); 74 | 75 | server.on('listening', () => { 76 | const url = `http://localhost:${server.address().port}`; 77 | 78 | if (!process.env.BROWSER) { 79 | console.error('The environment variable $BROWSER is not set. Falling back to default opening mechanism.'); 80 | open(url, { wait: false }); 81 | } else { 82 | console.error(`The environment variable $BROWSER is set to "${process.env.BROWSER}"`); 83 | spawn(process.env.BROWSER, [url], { detached: true }); 84 | } 85 | }); 86 | 87 | server.listen(port); 88 | server.timeout = config.serverTimeout; 89 | } 90 | 91 | function handler(request, response) { 92 | let contentType = config.contentType; 93 | const { backgroundColor: bg, foregroundColor: fg } = config; 94 | let stream = process.stdin; 95 | 96 | if (config.ansi) { 97 | contentType = 'text/html'; 98 | stream = stream.pipe(ansi(config.ansiOptions)); 99 | } 100 | 101 | if (!config.disableTabReplace) { 102 | const tab = ' '.repeat(config.tabLength); 103 | stream = stream.pipe(replaceStream(tab, config.tabReplace)); 104 | } 105 | 106 | if (!config.disableNewlineReplace) { 107 | stream = stream.pipe(replaceStream(os.EOL, config.newlineReplace)).pipe(replaceStream('\n', config.newlineReplace)); 108 | } 109 | 110 | response.setHeader('Content-Type', contentType); 111 | 112 | if (contentType === 'text/html') { 113 | const style = `body { background-color: ${bg}; color: ${fg}; font-family:Monaco, Menlo, monospace; padding:2em; } 114 | div#headline { position: fixed; top: 2em; right: 2em; text-align: right; } 115 | div#autoscroll { position: fixed; bottom: 2em; right: 2em; }`; 116 | 117 | response.write(` 118 | 119 |
Pipe from terminal to browser

started at: ${new Date()}
120 |
Auto scroll
121 |
`); 122 | } 123 | 124 | stream.pipe(response); 125 | 126 | response.on('finish', () => process.exit(0)); 127 | } 128 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bcat", 3 | "version": "3.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "bcat", 9 | "version": "3.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@kessler/ansi-html-stream": "^1.0.0", 13 | "isos": "0.0.3", 14 | "minimist": "^1.2.5", 15 | "open": "^10.1.0", 16 | "rc": "^1.2.8", 17 | "replacestream": "0.0.6", 18 | "text-table": "~0.2.0" 19 | }, 20 | "bin": { 21 | "bcat": "index.js" 22 | }, 23 | "devDependencies": { 24 | "eyes": "~0.1.8" 25 | } 26 | }, 27 | "node_modules/@kessler/ansi-html-stream": { 28 | "version": "1.0.0", 29 | "resolved": "https://registry.npmjs.org/@kessler/ansi-html-stream/-/ansi-html-stream-1.0.0.tgz", 30 | "integrity": "sha512-GgLuzOG2b6Ge4tiNzQABEjHvijPocTd2x8vCGR7TX4jORNDZPW5SQA2rNpxk33qhaSWaLQm7moXSFGwTJm7Khw==", 31 | "license": "MIT", 32 | "dependencies": { 33 | "escape-html": "0.0.1", 34 | "map-stream": "~0.0.1", 35 | "special-html": "0.0.1", 36 | "split": "~0.1.0", 37 | "xtend": "~1.0.3" 38 | }, 39 | "bin": { 40 | "ansi-html": "bin/ansi-html" 41 | } 42 | }, 43 | "node_modules/bundle-name": { 44 | "version": "4.1.0", 45 | "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", 46 | "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", 47 | "license": "MIT", 48 | "dependencies": { 49 | "run-applescript": "^7.0.0" 50 | }, 51 | "engines": { 52 | "node": ">=18" 53 | }, 54 | "funding": { 55 | "url": "https://github.com/sponsors/sindresorhus" 56 | } 57 | }, 58 | "node_modules/deep-extend": { 59 | "version": "0.6.0", 60 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 61 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 62 | "engines": { 63 | "node": ">=4.0.0" 64 | } 65 | }, 66 | "node_modules/default-browser": { 67 | "version": "5.2.1", 68 | "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", 69 | "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", 70 | "license": "MIT", 71 | "dependencies": { 72 | "bundle-name": "^4.1.0", 73 | "default-browser-id": "^5.0.0" 74 | }, 75 | "engines": { 76 | "node": ">=18" 77 | }, 78 | "funding": { 79 | "url": "https://github.com/sponsors/sindresorhus" 80 | } 81 | }, 82 | "node_modules/default-browser-id": { 83 | "version": "5.0.0", 84 | "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", 85 | "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", 86 | "license": "MIT", 87 | "engines": { 88 | "node": ">=18" 89 | }, 90 | "funding": { 91 | "url": "https://github.com/sponsors/sindresorhus" 92 | } 93 | }, 94 | "node_modules/define-lazy-prop": { 95 | "version": "3.0.0", 96 | "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", 97 | "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", 98 | "license": "MIT", 99 | "engines": { 100 | "node": ">=12" 101 | }, 102 | "funding": { 103 | "url": "https://github.com/sponsors/sindresorhus" 104 | } 105 | }, 106 | "node_modules/escape-html": { 107 | "version": "0.0.1", 108 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-0.0.1.tgz", 109 | "integrity": "sha512-n7MoTJIwtDy8dnBJgpwz0TXwzGq0pmO/vlagjiJafcWPj3cAHFVB6qKn8QsCtTEOcls7DDA/1Rxx6d27928osw==" 110 | }, 111 | "node_modules/eyes": { 112 | "version": "0.1.8", 113 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 114 | "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", 115 | "dev": true, 116 | "engines": { 117 | "node": "> 0.1.90" 118 | } 119 | }, 120 | "node_modules/ini": { 121 | "version": "1.3.8", 122 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 123 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" 124 | }, 125 | "node_modules/is-docker": { 126 | "version": "3.0.0", 127 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", 128 | "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", 129 | "license": "MIT", 130 | "bin": { 131 | "is-docker": "cli.js" 132 | }, 133 | "engines": { 134 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 135 | }, 136 | "funding": { 137 | "url": "https://github.com/sponsors/sindresorhus" 138 | } 139 | }, 140 | "node_modules/is-inside-container": { 141 | "version": "1.0.0", 142 | "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", 143 | "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", 144 | "license": "MIT", 145 | "dependencies": { 146 | "is-docker": "^3.0.0" 147 | }, 148 | "bin": { 149 | "is-inside-container": "cli.js" 150 | }, 151 | "engines": { 152 | "node": ">=14.16" 153 | }, 154 | "funding": { 155 | "url": "https://github.com/sponsors/sindresorhus" 156 | } 157 | }, 158 | "node_modules/is-wsl": { 159 | "version": "3.1.0", 160 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", 161 | "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", 162 | "license": "MIT", 163 | "dependencies": { 164 | "is-inside-container": "^1.0.0" 165 | }, 166 | "engines": { 167 | "node": ">=16" 168 | }, 169 | "funding": { 170 | "url": "https://github.com/sponsors/sindresorhus" 171 | } 172 | }, 173 | "node_modules/isos": { 174 | "version": "0.0.3", 175 | "resolved": "https://registry.npmjs.org/isos/-/isos-0.0.3.tgz", 176 | "integrity": "sha1-nUzBVy3X2ETfM/p9AbChKtKi1P0=" 177 | }, 178 | "node_modules/map-stream": { 179 | "version": "0.0.7", 180 | "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", 181 | "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", 182 | "license": "MIT" 183 | }, 184 | "node_modules/minimist": { 185 | "version": "1.2.6", 186 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 187 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" 188 | }, 189 | "node_modules/open": { 190 | "version": "10.1.0", 191 | "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", 192 | "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", 193 | "license": "MIT", 194 | "dependencies": { 195 | "default-browser": "^5.2.1", 196 | "define-lazy-prop": "^3.0.0", 197 | "is-inside-container": "^1.0.0", 198 | "is-wsl": "^3.1.0" 199 | }, 200 | "engines": { 201 | "node": ">=18" 202 | }, 203 | "funding": { 204 | "url": "https://github.com/sponsors/sindresorhus" 205 | } 206 | }, 207 | "node_modules/rc": { 208 | "version": "1.2.8", 209 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 210 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 211 | "dependencies": { 212 | "deep-extend": "^0.6.0", 213 | "ini": "~1.3.0", 214 | "minimist": "^1.2.0", 215 | "strip-json-comments": "~2.0.1" 216 | }, 217 | "bin": { 218 | "rc": "cli.js" 219 | } 220 | }, 221 | "node_modules/replacestream": { 222 | "version": "0.0.6", 223 | "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-0.0.6.tgz", 224 | "integrity": "sha1-CnqhV+pxPpZJJc2gQ14KnY9ZYKU=", 225 | "dependencies": { 226 | "through": "~2.3.4" 227 | } 228 | }, 229 | "node_modules/replacestream/node_modules/through": { 230 | "version": "2.3.8", 231 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 232 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 233 | }, 234 | "node_modules/run-applescript": { 235 | "version": "7.0.0", 236 | "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", 237 | "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", 238 | "license": "MIT", 239 | "engines": { 240 | "node": ">=18" 241 | }, 242 | "funding": { 243 | "url": "https://github.com/sponsors/sindresorhus" 244 | } 245 | }, 246 | "node_modules/special-html": { 247 | "version": "0.0.1", 248 | "resolved": "https://registry.npmjs.org/special-html/-/special-html-0.0.1.tgz", 249 | "integrity": "sha512-mrVvUe6eJmq7RsKCTwjOFwE1vMfSQ6GEI0AutWa401JPmGpSvQZTNln+waihifcxsLeZGyn1eli1M0jyNSeMaA==", 250 | "license": "MIT" 251 | }, 252 | "node_modules/split": { 253 | "version": "0.1.2", 254 | "resolved": "https://registry.npmjs.org/split/-/split-0.1.2.tgz", 255 | "integrity": "sha512-KovAcDCS2xGeulhU2zVUUglt9/M6yIZVtKqsT0uOaA0UuEyUrxQoC5EhVt5doxVyodJ6trD3Q79fbIiD6bqb4g==", 256 | "dependencies": { 257 | "through": "1" 258 | }, 259 | "engines": { 260 | "node": "*" 261 | } 262 | }, 263 | "node_modules/strip-json-comments": { 264 | "version": "2.0.1", 265 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 266 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 267 | "engines": { 268 | "node": ">=0.10.0" 269 | } 270 | }, 271 | "node_modules/text-table": { 272 | "version": "0.2.0", 273 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 274 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" 275 | }, 276 | "node_modules/through": { 277 | "version": "1.1.2", 278 | "resolved": "https://registry.npmjs.org/through/-/through-1.1.2.tgz", 279 | "integrity": "sha512-YG7jdC/XCqsooOdR2LJpeuQ5WnuYnHohUMJq4xMN09rbr81rli6JfZbGa07dWJg24qb8h6mGC+0G74eak9hrnw==", 280 | "license": "MIT" 281 | }, 282 | "node_modules/xtend": { 283 | "version": "1.0.3", 284 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-1.0.3.tgz", 285 | "integrity": "sha512-wv78b3q8kHDveC/C7Yq/UUrJXsAAM1t/j5m28h/ZlqYy0+eqByglhsWR88D2j3VImQzZlNIDsSbZ3QItwgWEGw==", 286 | "engines": { 287 | "node": ">=0.4" 288 | } 289 | } 290 | }, 291 | "dependencies": { 292 | "@kessler/ansi-html-stream": { 293 | "version": "1.0.0", 294 | "resolved": "https://registry.npmjs.org/@kessler/ansi-html-stream/-/ansi-html-stream-1.0.0.tgz", 295 | "integrity": "sha512-GgLuzOG2b6Ge4tiNzQABEjHvijPocTd2x8vCGR7TX4jORNDZPW5SQA2rNpxk33qhaSWaLQm7moXSFGwTJm7Khw==", 296 | "requires": { 297 | "escape-html": "0.0.1", 298 | "map-stream": "~0.0.1", 299 | "special-html": "0.0.1", 300 | "split": "~0.1.0", 301 | "xtend": "~1.0.3" 302 | } 303 | }, 304 | "bundle-name": { 305 | "version": "4.1.0", 306 | "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", 307 | "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", 308 | "requires": { 309 | "run-applescript": "^7.0.0" 310 | } 311 | }, 312 | "deep-extend": { 313 | "version": "0.6.0", 314 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 315 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" 316 | }, 317 | "default-browser": { 318 | "version": "5.2.1", 319 | "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", 320 | "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", 321 | "requires": { 322 | "bundle-name": "^4.1.0", 323 | "default-browser-id": "^5.0.0" 324 | } 325 | }, 326 | "default-browser-id": { 327 | "version": "5.0.0", 328 | "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", 329 | "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==" 330 | }, 331 | "define-lazy-prop": { 332 | "version": "3.0.0", 333 | "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", 334 | "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==" 335 | }, 336 | "escape-html": { 337 | "version": "0.0.1", 338 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-0.0.1.tgz", 339 | "integrity": "sha512-n7MoTJIwtDy8dnBJgpwz0TXwzGq0pmO/vlagjiJafcWPj3cAHFVB6qKn8QsCtTEOcls7DDA/1Rxx6d27928osw==" 340 | }, 341 | "eyes": { 342 | "version": "0.1.8", 343 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 344 | "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", 345 | "dev": true 346 | }, 347 | "ini": { 348 | "version": "1.3.8", 349 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 350 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" 351 | }, 352 | "is-docker": { 353 | "version": "3.0.0", 354 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", 355 | "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==" 356 | }, 357 | "is-inside-container": { 358 | "version": "1.0.0", 359 | "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", 360 | "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", 361 | "requires": { 362 | "is-docker": "^3.0.0" 363 | } 364 | }, 365 | "is-wsl": { 366 | "version": "3.1.0", 367 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", 368 | "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", 369 | "requires": { 370 | "is-inside-container": "^1.0.0" 371 | } 372 | }, 373 | "isos": { 374 | "version": "0.0.3", 375 | "resolved": "https://registry.npmjs.org/isos/-/isos-0.0.3.tgz", 376 | "integrity": "sha1-nUzBVy3X2ETfM/p9AbChKtKi1P0=" 377 | }, 378 | "map-stream": { 379 | "version": "0.0.7", 380 | "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", 381 | "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==" 382 | }, 383 | "minimist": { 384 | "version": "1.2.6", 385 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 386 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" 387 | }, 388 | "open": { 389 | "version": "10.1.0", 390 | "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", 391 | "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", 392 | "requires": { 393 | "default-browser": "^5.2.1", 394 | "define-lazy-prop": "^3.0.0", 395 | "is-inside-container": "^1.0.0", 396 | "is-wsl": "^3.1.0" 397 | } 398 | }, 399 | "rc": { 400 | "version": "1.2.8", 401 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 402 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 403 | "requires": { 404 | "deep-extend": "^0.6.0", 405 | "ini": "~1.3.0", 406 | "minimist": "^1.2.0", 407 | "strip-json-comments": "~2.0.1" 408 | } 409 | }, 410 | "replacestream": { 411 | "version": "0.0.6", 412 | "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-0.0.6.tgz", 413 | "integrity": "sha1-CnqhV+pxPpZJJc2gQ14KnY9ZYKU=", 414 | "requires": { 415 | "through": "~2.3.4" 416 | }, 417 | "dependencies": { 418 | "through": { 419 | "version": "2.3.8", 420 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 421 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 422 | } 423 | } 424 | }, 425 | "run-applescript": { 426 | "version": "7.0.0", 427 | "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", 428 | "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==" 429 | }, 430 | "special-html": { 431 | "version": "0.0.1", 432 | "resolved": "https://registry.npmjs.org/special-html/-/special-html-0.0.1.tgz", 433 | "integrity": "sha512-mrVvUe6eJmq7RsKCTwjOFwE1vMfSQ6GEI0AutWa401JPmGpSvQZTNln+waihifcxsLeZGyn1eli1M0jyNSeMaA==" 434 | }, 435 | "split": { 436 | "version": "0.1.2", 437 | "resolved": "https://registry.npmjs.org/split/-/split-0.1.2.tgz", 438 | "integrity": "sha512-KovAcDCS2xGeulhU2zVUUglt9/M6yIZVtKqsT0uOaA0UuEyUrxQoC5EhVt5doxVyodJ6trD3Q79fbIiD6bqb4g==", 439 | "requires": { 440 | "through": "1" 441 | } 442 | }, 443 | "strip-json-comments": { 444 | "version": "2.0.1", 445 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 446 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" 447 | }, 448 | "text-table": { 449 | "version": "0.2.0", 450 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 451 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" 452 | }, 453 | "through": { 454 | "version": "1.1.2", 455 | "resolved": "https://registry.npmjs.org/through/-/through-1.1.2.tgz", 456 | "integrity": "sha512-YG7jdC/XCqsooOdR2LJpeuQ5WnuYnHohUMJq4xMN09rbr81rli6JfZbGa07dWJg24qb8h6mGC+0G74eak9hrnw==" 457 | }, 458 | "xtend": { 459 | "version": "1.0.3", 460 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-1.0.3.tgz", 461 | "integrity": "sha512-wv78b3q8kHDveC/C7Yq/UUrJXsAAM1t/j5m28h/ZlqYy0+eqByglhsWR88D2j3VImQzZlNIDsSbZ3QItwgWEGw==" 462 | } 463 | } 464 | } 465 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bcat", 3 | "version": "3.0.0", 4 | "description": "A pipe to browser utility", 5 | "main": "index.mjs", 6 | "bin": { 7 | "bcat": "index.mjs" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/kessler/node-bcat" 15 | }, 16 | "keywords": [ 17 | "pipe", 18 | "browser", 19 | "cat", 20 | "bcat" 21 | ], 22 | "author": "Yaniv Kessler", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/kessler/node-bcat/issues" 26 | }, 27 | "dependencies": { 28 | "@kessler/ansi-html-stream": "^1.0.0", 29 | "isos": "0.0.3", 30 | "minimist": "^1.2.5", 31 | "open": "^10.1.0", 32 | "rc": "^1.2.8", 33 | "replacestream": "0.0.6", 34 | "text-table": "~0.2.0" 35 | }, 36 | "devDependencies": { 37 | "eyes": "~0.1.8" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 123 4 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var inspect = require('eyes').inspector(/*{ stream: null }*/); 2 | var util = require('util') 3 | 4 | var obj = { 5 | x: 1, 6 | y: 2, 7 | f: { 8 | g: 3, 9 | z: 9 10 | } 11 | } 12 | 13 | console.log('abcdefg foo bar') 14 | inspect(obj) 15 | 16 | setInterval(function () { 17 | inspect(obj) 18 | }, 1000) 19 | -------------------------------------------------------------------------------- /usage.js: -------------------------------------------------------------------------------- 1 | var table = require('text-table'); 2 | 3 | module.exports = table([ 4 | ['Options:\n'], 5 | ['--port', 'set a port for this bcat execution\n', '[default: random port]'], 6 | ['--contentType', 'content type header, must be lower case', '[default: "text/html"]\n'], 7 | ['--backgroundColor', '(only in text/html) ', '[default: "#000000"]\n'], 8 | ['--foregroundColor', '(only in text/html) ', '[default: "#ffffff"]\n'], 9 | ['--tabLength', 'length of a tab in spaces', '[default: 4]\n'], 10 | ['--tabReplace', 'tab replacement', '[default: "    "\n'], 11 | ['--disableTabReplace', 'disable tab replacement', '[default: false]\n'], 12 | ['--newlineReplace', 'new line replacement', '[default: "
"\n'], 13 | ['--disableNewlineReplace', 'disable new line replacement', '[default: false]\n'], 14 | ['--ansi', 'show colorful ansi (implies text/html)', '[default: true]\n'], 15 | ['--ansiOptions', 'override replacement of ansi black color\n', ''], 16 | ['--scrollDownInterval', 'interval to execute javascript scroll down', '[default: 1000 (ms)]\n'], 17 | ['--serverTimeout', 'http://nodejs.org/api/http.html#http_server_timeout', '[default: 0 (no timeout)]\n'], 18 | ['--command', 'the command to launch the browser', '[default: osx: open, windows: start, other: xdg-open]\n'] 19 | ]); 20 | --------------------------------------------------------------------------------