├── .npmrc ├── .gitignore ├── tsconfig.json ├── .editorconfig ├── .github └── workflows │ └── test.yml ├── test.js ├── license ├── package.json ├── source └── index.ts └── readme.md /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@sindresorhus/tsconfig/tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: [push] 3 | 4 | jobs: 5 | test: 6 | name: Node.js ${{ matrix.node_version }} 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node_version: [12, 14, 16] 11 | 12 | steps: 13 | - uses: actions/checkout@master 14 | - name: Use Node.js ${{ matrix.node_version }} 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: ${{ matrix.node_version }} 18 | - run: npm install 19 | - run: npm test 20 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import sinon from 'sinon'; 3 | import patch from './dist/index.js'; 4 | 5 | test('intercept console.log()', t => { 6 | const write = sinon.spy(); 7 | const restore = patch(write); 8 | 9 | console.log('test'); 10 | restore(); 11 | 12 | t.true(write.called); 13 | t.deepEqual(write.firstCall.args, ['stdout', 'test\n']); 14 | }); 15 | 16 | test('intercept console.error()', t => { 17 | const write = sinon.spy(); 18 | const restore = patch(write); 19 | 20 | console.error('test'); 21 | restore(); 22 | 23 | t.true(write.called); 24 | t.deepEqual(write.firstCall.args, ['stderr', 'test\n']); 25 | }); 26 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Vadim Demedes (https://vadimdemedes.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "patch-console", 3 | "version": "2.0.0", 4 | "description": "Patch console methods to intercept output", 5 | "license": "MIT", 6 | "repository": "vadimdemedes/patch-console", 7 | "author": { 8 | "name": "vdemedes", 9 | "email": "vdemedes@gmail.com", 10 | "url": "https://github.com/vadimdemedes" 11 | }, 12 | "type": "module", 13 | "exports": "./dist/index.js", 14 | "engines": { 15 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 16 | }, 17 | "scripts": { 18 | "build": "tsc", 19 | "dev": "tsc --watch", 20 | "prepare": "npm run build", 21 | "pretest": "npm run build", 22 | "test": "prettier --check source && xo && ava" 23 | }, 24 | "files": [ 25 | "dist" 26 | ], 27 | "keywords": [ 28 | "stdout", 29 | "stderr", 30 | "patch", 31 | "console", 32 | "intercept", 33 | "log", 34 | "logs" 35 | ], 36 | "devDependencies": { 37 | "@sindresorhus/tsconfig": "^2.0.0", 38 | "@types/node": "^17.0.14", 39 | "@vdemedes/prettier-config": "^2.0.1", 40 | "ava": "^4.0.1", 41 | "prettier": "^2.5.1", 42 | "sinon": "^9.0.2", 43 | "typescript": "^4.5.5", 44 | "xo": "^0.47.0" 45 | }, 46 | "prettier": "@vdemedes/prettier-config", 47 | "xo": { 48 | "prettier": true 49 | }, 50 | "ava": { 51 | "serial": true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /source/index.ts: -------------------------------------------------------------------------------- 1 | import {PassThrough} from 'node:stream'; 2 | 3 | const consoleMethods = [ 4 | 'assert', 5 | 'count', 6 | 'countReset', 7 | 'debug', 8 | 'dir', 9 | 'dirxml', 10 | 'error', 11 | 'group', 12 | 'groupCollapsed', 13 | 'groupEnd', 14 | 'info', 15 | 'log', 16 | 'table', 17 | 'time', 18 | 'timeEnd', 19 | 'timeLog', 20 | 'trace', 21 | 'warn', 22 | ]; 23 | 24 | let originalMethods: Record = {}; 25 | 26 | type Callback = (stream: 'stdout' | 'stderr', data: string) => void; 27 | type Restore = () => void; 28 | 29 | const patchConsole = (callback: Callback): Restore => { 30 | const stdout = new PassThrough(); 31 | const stderr = new PassThrough(); 32 | 33 | (stdout as any).write = (data: string): void => { 34 | callback('stdout', data); 35 | }; 36 | 37 | (stderr as any).write = (data: string): void => { 38 | callback('stderr', data); 39 | }; 40 | 41 | const internalConsole = new console.Console(stdout, stderr); 42 | 43 | for (const method of consoleMethods) { 44 | originalMethods[method] = (console as any)[method]; 45 | 46 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 47 | (console as any)[method] = (internalConsole as any)[method]; 48 | } 49 | 50 | return () => { 51 | for (const method of consoleMethods) { 52 | (console as any)[method] = originalMethods[method]; 53 | } 54 | 55 | originalMethods = {}; 56 | }; 57 | }; 58 | 59 | export default patchConsole; 60 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # patch-console ![test](https://github.com/vadimdemedes/patch-console/workflows/test/badge.svg) 2 | 3 | > Patch console methods to intercept output 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install patch-console 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | import patchConsole from 'patch-console'; 15 | 16 | const restore = patchConsole((stream, data) => { 17 | // stream = 'stdout' 18 | // data = "Hello World" 19 | }); 20 | 21 | console.log('Hello World'); 22 | 23 | // Restore original methods 24 | restore(); 25 | ``` 26 | 27 | ## API 28 | 29 | ### patchConsole(callback) 30 | 31 | After this function is called, output from console methods will be intercepted and won't show up in the actual stdout or stderr stream. 32 | To restore original console methods and stop intercepting output, call the function which `patchConsole()` returns. 33 | 34 | #### callback 35 | 36 | Type: `Function` 37 | 38 | Function that will be called when output from one of the console methods is intercepted. 39 | First argument is name of the stream (`"stdout"` or `"stderr"`), second argument is output itself. 40 | 41 | ## Console methods 42 | 43 | This module intercepts the following methods: 44 | 45 | - `console.assert()` 46 | - `console.count()` 47 | - `console.countReset()` 48 | - `console.debug()` 49 | - `console.dir()` 50 | - `console.dirxml()` 51 | - `console.error()` 52 | - `console.group()` 53 | - `console.groupCollapsed()` 54 | - `console.groupEnd()` 55 | - `console.info()` 56 | - `console.log()` 57 | - `console.table()` 58 | - `console.time()` 59 | - `console.timeEnd()` 60 | - `console.timeLog()` 61 | - `console.trace()` 62 | - `console.warn()` 63 | --------------------------------------------------------------------------------