├── .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 | 
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 | 
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 |
--------------------------------------------------------------------------------