From 5b9ef9bc30b66d58e200f0132490b07a51227f68 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova Date: Mon, 28 Oct 2024 16:37:49 +0100 Subject: [PATCH 1/6] Convert plugin-console-breadcrumbs to TypeScript --- packages/core/lib/es-utils/reduce.d.ts | 2 +- .../console-breadcrumbs.js | 47 ------------ .../plugin-console-breadcrumbs/package.json | 17 ++++- .../rollup.config.npm.mjs | 5 ++ .../src/console-breadcrumbs.ts | 73 +++++++++++++++++++ .../test/console-breadcrumbs.test.ts | 2 +- .../plugin-console-breadcrumbs/tsconfig.json | 7 ++ tsconfig.json | 1 - 8 files changed, 102 insertions(+), 52 deletions(-) delete mode 100644 packages/plugin-console-breadcrumbs/console-breadcrumbs.js create mode 100644 packages/plugin-console-breadcrumbs/rollup.config.npm.mjs create mode 100644 packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts create mode 100644 packages/plugin-console-breadcrumbs/tsconfig.json diff --git a/packages/core/lib/es-utils/reduce.d.ts b/packages/core/lib/es-utils/reduce.d.ts index 576384d933..f77c6a8dc8 100644 --- a/packages/core/lib/es-utils/reduce.d.ts +++ b/packages/core/lib/es-utils/reduce.d.ts @@ -1 +1 @@ -export default function reduce(arr: T[], fn: (accum: any, item: T) => any, accum: any): any +export default function reduce(arr: T[], fn: (accum: any, arg: any, item: T) => any, accum: any): any diff --git a/packages/plugin-console-breadcrumbs/console-breadcrumbs.js b/packages/plugin-console-breadcrumbs/console-breadcrumbs.js deleted file mode 100644 index f009c48247..0000000000 --- a/packages/plugin-console-breadcrumbs/console-breadcrumbs.js +++ /dev/null @@ -1,47 +0,0 @@ -const map = require('@bugsnag/core/lib/es-utils/map') -const reduce = require('@bugsnag/core/lib/es-utils/reduce') -const filter = require('@bugsnag/core/lib/es-utils/filter') - -/* - * Leaves breadcrumbs when console log methods are called - */ -exports.load = (client) => { - const isDev = /^(local-)?dev(elopment)?$/.test(client._config.releaseStage) - - if (isDev || !client._isBreadcrumbTypeEnabled('log')) return - - map(CONSOLE_LOG_METHODS, method => { - const original = console[method] - console[method] = (...args) => { - client.leaveBreadcrumb('Console output', reduce(args, (accum, arg, i) => { - // do the best/simplest stringification of each argument - let stringified = '[Unknown value]' - // this may fail if the input is: - // - an object whose [[Prototype]] is null (no toString) - // - an object with a broken toString or @@toPrimitive implementation - try { stringified = String(arg) } catch (e) {} - // if it stringifies to [object Object] attempt to JSON stringify - if (stringified === '[object Object]') { - // catch stringify errors and fallback to [object Object] - try { stringified = JSON.stringify(arg) } catch (e) {} - } - accum[`[${i}]`] = stringified - return accum - }, { - severity: method.indexOf('group') === 0 ? 'log' : method - }), 'log') - original.apply(console, args) - } - console[method]._restore = () => { console[method] = original } - }) -} - -if (process.env.NODE_ENV !== 'production') { - exports.destroy = () => CONSOLE_LOG_METHODS.forEach(method => { - if (typeof console[method]._restore === 'function') console[method]._restore() - }) -} - -const CONSOLE_LOG_METHODS = filter(['log', 'debug', 'info', 'warn', 'error'], method => - typeof console !== 'undefined' && typeof console[method] === 'function' -) diff --git a/packages/plugin-console-breadcrumbs/package.json b/packages/plugin-console-breadcrumbs/package.json index d8f6ad0965..9c9d52f414 100644 --- a/packages/plugin-console-breadcrumbs/package.json +++ b/packages/plugin-console-breadcrumbs/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-console-breadcrumbs", "version": "8.1.1", - "main": "console-breadcrumbs.js", + "main": "dist/console-breadcrumbs.js", + "types": "dist/types/throttle.d.ts", + "exports": { + ".": { + "types": "./dist/types/throttle.d.ts", + "default": "./dist/throttle.js", + "import": "./dist/throttle.mjs" + } + }, "description": "@bugsnag/js plugin to record console log method calls as breadcrumbs", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,7 +20,7 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], "author": "Bugsnag", "license": "MIT", @@ -21,5 +29,10 @@ }, "peerDependencies": { "@bugsnag/core": "^8.0.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*" } } diff --git a/packages/plugin-console-breadcrumbs/rollup.config.npm.mjs b/packages/plugin-console-breadcrumbs/rollup.config.npm.mjs new file mode 100644 index 0000000000..c4ee7de9a3 --- /dev/null +++ b/packages/plugin-console-breadcrumbs/rollup.config.npm.mjs @@ -0,0 +1,5 @@ +import createRollupConfig from "../../.rollup/index.mjs"; + +export default createRollupConfig({ + input: "src/console-breadcrumbs.ts" +}); diff --git a/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts b/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts new file mode 100644 index 0000000000..daf3d8ccfe --- /dev/null +++ b/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts @@ -0,0 +1,73 @@ +import { Plugin } from '@bugsnag/core' +import filter from '@bugsnag/core/lib/es-utils/filter' +import map from '@bugsnag/core/lib/es-utils/map' +import reduce from '@bugsnag/core/lib/es-utils/reduce' + +/* + * Leaves breadcrumbs when console log methods are called + */ +const plugin: Plugin = { + load: client => { + // @ts-expect-error _config is private API + const isDev = /^(local-)?dev(elopment)?$/.test(client._config.releaseStage) + + // @ts-expect-error isBreadcrumbTypeEnabled is private API + if (isDev || !client._isBreadcrumbTypeEnabled('log')) return + + map(CONSOLE_LOG_METHODS, method => { + const original = (console as any)[method] + console[method] = (...args: any[]) => { + client.leaveBreadcrumb( + 'Console output', + reduce( + args, + (accum: any, arg: any, i: any) => { + // do the best/simplest stringification of each argument + let stringified = '[Unknown value]' + // this may fail if the input is: + // - an object whose [[Prototype]] is null (no toString) + // - an object with a broken toString or @@toPrimitive implementation + try { + stringified = String(arg) + } catch (e) {} + // if it stringifies to [object Object] attempt to JSON stringify + if (stringified === '[object Object]') { + // catch stringify errors and fallback to [object Object] + try { + stringified = JSON.stringify(arg) + } catch (e) {} + } + accum[`[${i}]`] = stringified + return accum + }, + { + severity: method.indexOf('group') === 0 ? 'log' : method + } + ), + 'log' + ) + original.apply(console, args) + } + (console as any)[method]._restore = () => { + (console as any)[method] = original + } + }) + } +} + +if (process.env.NODE_ENV !== 'production') { + plugin.destroy = () => + CONSOLE_LOG_METHODS.forEach(method => { + if (typeof (console as any)[method]._restore === 'function') { + (console as any)[method]._restore() + } + }) +} + +const CONSOLE_LOG_METHODS = filter( + ['log', 'debug', 'info', 'warn', 'error'], + method => + typeof console !== 'undefined' && typeof (console as any)[method] === 'function' +) + +export default plugin diff --git a/packages/plugin-console-breadcrumbs/test/console-breadcrumbs.test.ts b/packages/plugin-console-breadcrumbs/test/console-breadcrumbs.test.ts index a6f5799b13..d952d76921 100644 --- a/packages/plugin-console-breadcrumbs/test/console-breadcrumbs.test.ts +++ b/packages/plugin-console-breadcrumbs/test/console-breadcrumbs.test.ts @@ -1,4 +1,4 @@ -import plugin from '../' +import plugin from '../src/console-breadcrumbs' import Client from '@bugsnag/core/client' diff --git a/packages/plugin-console-breadcrumbs/tsconfig.json b/packages/plugin-console-breadcrumbs/tsconfig.json new file mode 100644 index 0000000000..9478c51300 --- /dev/null +++ b/packages/plugin-console-breadcrumbs/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "target": "ES2020" + } +} diff --git a/tsconfig.json b/tsconfig.json index 25fad7868e..3ba120f783 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -88,7 +88,6 @@ "packages/plugin-node-device", "packages/plugin-node-surrounding-code", "packages/plugin-node-uncaught-exception", - "packages/plugin-console-breadcrumbs", "packages/plugin-browser-session", "packages/browser" ], From 42a41bbdd1f9386b2ddff3a02192a84993bfc078 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova Date: Mon, 28 Oct 2024 16:56:28 +0100 Subject: [PATCH 2/6] fix: process TS error --- packages/plugin-console-breadcrumbs/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/plugin-console-breadcrumbs/tsconfig.json b/packages/plugin-console-breadcrumbs/tsconfig.json index 9478c51300..4fe20b6abd 100644 --- a/packages/plugin-console-breadcrumbs/tsconfig.json +++ b/packages/plugin-console-breadcrumbs/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "include": ["src/**/*.ts"], "compilerOptions": { - "target": "ES2020" + "target": "ES2020", + "types": ["node"] } } From 9b805c49c0140cabe102005e6f1ff94dea7bf771 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova Date: Mon, 28 Oct 2024 17:23:50 +0100 Subject: [PATCH 3/6] fix: console methods type Co-authored-by: Ben Wilson --- .../src/console-breadcrumbs.ts | 21 +++++++++++-------- .../test/console-breadcrumbs.test.ts | 16 +++++++------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts b/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts index daf3d8ccfe..6717c1d769 100644 --- a/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts +++ b/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts @@ -15,13 +15,13 @@ const plugin: Plugin = { if (isDev || !client._isBreadcrumbTypeEnabled('log')) return map(CONSOLE_LOG_METHODS, method => { - const original = (console as any)[method] - console[method] = (...args: any[]) => { + const original = console[method] + console[method] = (...args) => { client.leaveBreadcrumb( 'Console output', reduce( args, - (accum: any, arg: any, i: any) => { + (accum, arg, i) => { // do the best/simplest stringification of each argument let stringified = '[Unknown value]' // this may fail if the input is: @@ -48,8 +48,9 @@ const plugin: Plugin = { ) original.apply(console, args) } - (console as any)[method]._restore = () => { - (console as any)[method] = original + // @ts-expect-error _restore is added to be able to remove our monkey patched code + console[method]._restore = () => { + console[method] = original } }) } @@ -58,16 +59,18 @@ const plugin: Plugin = { if (process.env.NODE_ENV !== 'production') { plugin.destroy = () => CONSOLE_LOG_METHODS.forEach(method => { - if (typeof (console as any)[method]._restore === 'function') { - (console as any)[method]._restore() + // @ts-expect-error _restore is added to be able to remove our monkey patched code + if (typeof console[method]._restore === 'function') { + // @ts-expect-error _restore is added to be able to remove our monkey patched code + console[method]._restore() } }) } const CONSOLE_LOG_METHODS = filter( - ['log', 'debug', 'info', 'warn', 'error'], + ['log', 'debug', 'info', 'warn', 'error'] as const, method => - typeof console !== 'undefined' && typeof (console as any)[method] === 'function' + typeof console !== 'undefined' && typeof console[method] === 'function' ) export default plugin diff --git a/packages/plugin-console-breadcrumbs/test/console-breadcrumbs.test.ts b/packages/plugin-console-breadcrumbs/test/console-breadcrumbs.test.ts index d952d76921..46ca7a8f78 100644 --- a/packages/plugin-console-breadcrumbs/test/console-breadcrumbs.test.ts +++ b/packages/plugin-console-breadcrumbs/test/console-breadcrumbs.test.ts @@ -27,7 +27,7 @@ describe('plugin: console breadcrumbs', () => { expect(c._breadcrumbs[2].metadata['[0]']).toBe('{"foo":[1,2,3,"four"]}') expect(c._breadcrumbs[2].metadata['[1]']).toBe('{"pets":{"cat":"scratcher","dog":"pupper","rabbit":"sniffer"}}') // undo the global side effects of wrapping console.* for the rest of the tests - plugin.destroy() + plugin.destroy?.() }) it('should not throw when an object without toString is logged', () => { @@ -36,48 +36,48 @@ describe('plugin: console breadcrumbs', () => { expect(c._breadcrumbs.length).toBe(1) expect(c._breadcrumbs[0].message).toBe('Console output') expect(c._breadcrumbs[0].metadata['[0]']).toBe('[Unknown value]') - plugin.destroy() + plugin.destroy?.() }) it('should not be enabled when enabledBreadcrumbTypes=[]', () => { const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', enabledBreadcrumbTypes: [], plugins: [plugin] }) console.log(123) expect(c._breadcrumbs.length).toBe(0) - plugin.destroy() + plugin.destroy?.() }) it('should be enabled when enabledBreadcrumbTypes=null', () => { const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', enabledBreadcrumbTypes: null, plugins: [plugin] }) console.log(123) expect(c._breadcrumbs).toHaveLength(1) - plugin.destroy() + plugin.destroy?.() }) it('should be enabled when enabledBreadcrumbTypes=["log"]', () => { const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', enabledBreadcrumbTypes: ['log'], plugins: [plugin] }) console.log(123) expect(c._breadcrumbs.length).toBe(1) - plugin.destroy() + plugin.destroy?.() }) it('should be not enabled by default when releaseStage=development', () => { const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', releaseStage: 'development', plugins: [plugin] }) console.log(123) expect(c._breadcrumbs.length).toBe(0) - plugin.destroy() + plugin.destroy?.() }) it('should be not enabled by default when releaseStage=dev', () => { const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', releaseStage: 'dev', plugins: [plugin] }) console.log(123) expect(c._breadcrumbs.length).toBe(0) - plugin.destroy() + plugin.destroy?.() }) it('should be not enabled by default when releaseStage=local-dev', () => { const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', releaseStage: 'local-dev', plugins: [plugin] }) console.log(123) expect(c._breadcrumbs.length).toBe(0) - plugin.destroy() + plugin.destroy?.() }) }) From 7e88975818c1e259ac2208c5acb5c3d57b9c1fb0 Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Tue, 29 Oct 2024 09:59:30 +0000 Subject: [PATCH 4/6] chore: :label: fix rollup build by updating types --- packages/plugin-console-breadcrumbs/rollup.config.npm.mjs | 3 ++- .../plugin-console-breadcrumbs/src/console-breadcrumbs.ts | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/plugin-console-breadcrumbs/rollup.config.npm.mjs b/packages/plugin-console-breadcrumbs/rollup.config.npm.mjs index c4ee7de9a3..6cc0db1836 100644 --- a/packages/plugin-console-breadcrumbs/rollup.config.npm.mjs +++ b/packages/plugin-console-breadcrumbs/rollup.config.npm.mjs @@ -1,5 +1,6 @@ import createRollupConfig from "../../.rollup/index.mjs"; export default createRollupConfig({ - input: "src/console-breadcrumbs.ts" + input: "src/console-breadcrumbs.ts", + external: ["@bugsnag/core/lib/es-utils/filter", "@bugsnag/core/lib/es-utils/map", "@bugsnag/core/lib/es-utils/reduce"] }); diff --git a/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts b/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts index 6717c1d769..06ab7930ff 100644 --- a/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts +++ b/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts @@ -16,7 +16,7 @@ const plugin: Plugin = { map(CONSOLE_LOG_METHODS, method => { const original = console[method] - console[method] = (...args) => { + console[method] = (...args: any) => { client.leaveBreadcrumb( 'Console output', reduce( @@ -67,8 +67,8 @@ if (process.env.NODE_ENV !== 'production') { }) } -const CONSOLE_LOG_METHODS = filter( - ['log', 'debug', 'info', 'warn', 'error'] as const, +const CONSOLE_LOG_METHODS: Array<'log' | 'debug' | 'info' | 'warn' | 'error'> = filter( + ['log', 'debug', 'info', 'warn', 'error'], method => typeof console !== 'undefined' && typeof console[method] === 'function' ) From 84e527afa5138674a175adec1c389498f2a9078c Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Wed, 30 Oct 2024 11:56:57 +0000 Subject: [PATCH 5/6] chore: :label: fix types and remove usage of ts-expect-error --- packages/core/lib/es-utils/reduce.d.ts | 2 +- .../src/console-breadcrumbs.ts | 36 +++++++++++-------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/packages/core/lib/es-utils/reduce.d.ts b/packages/core/lib/es-utils/reduce.d.ts index f77c6a8dc8..4a468b0a72 100644 --- a/packages/core/lib/es-utils/reduce.d.ts +++ b/packages/core/lib/es-utils/reduce.d.ts @@ -1 +1 @@ -export default function reduce(arr: T[], fn: (accum: any, arg: any, item: T) => any, accum: any): any +export default function reduce(arr: T[], fn: (accum: any, item: T, index: number, arr: T[]) => any, accum: any): any diff --git a/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts b/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts index 06ab7930ff..15b2eb14f9 100644 --- a/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts +++ b/packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts @@ -1,18 +1,27 @@ -import { Plugin } from '@bugsnag/core' +import { Client, Config, Plugin } from '@bugsnag/core' import filter from '@bugsnag/core/lib/es-utils/filter' import map from '@bugsnag/core/lib/es-utils/map' import reduce from '@bugsnag/core/lib/es-utils/reduce' +type ConsoleMethod = 'log' | 'debug' | 'info' | 'warn' | 'error' + +interface ClientWithInternals extends Client { + _config: Required + _isBreadcrumbTypeEnabled: (type: ConsoleMethod) => boolean +} + +type ConsoleWithRestore = Console & { + [key in ConsoleMethod]: typeof console[ConsoleMethod] & { _restore: () => void } +} + /* * Leaves breadcrumbs when console log methods are called */ const plugin: Plugin = { - load: client => { - // @ts-expect-error _config is private API - const isDev = /^(local-)?dev(elopment)?$/.test(client._config.releaseStage) + load: (client) => { + const isDev = /^(local-)?dev(elopment)?$/.test((client as ClientWithInternals)._config.releaseStage) - // @ts-expect-error isBreadcrumbTypeEnabled is private API - if (isDev || !client._isBreadcrumbTypeEnabled('log')) return + if (isDev || !(client as ClientWithInternals)._isBreadcrumbTypeEnabled('log')) return map(CONSOLE_LOG_METHODS, method => { const original = console[method] @@ -48,8 +57,7 @@ const plugin: Plugin = { ) original.apply(console, args) } - // @ts-expect-error _restore is added to be able to remove our monkey patched code - console[method]._restore = () => { + (console as ConsoleWithRestore)[method]._restore = () => { console[method] = original } }) @@ -57,17 +65,17 @@ const plugin: Plugin = { } if (process.env.NODE_ENV !== 'production') { - plugin.destroy = () => + plugin.destroy = () => { + const consoleWithRestore = console as ConsoleWithRestore CONSOLE_LOG_METHODS.forEach(method => { - // @ts-expect-error _restore is added to be able to remove our monkey patched code - if (typeof console[method]._restore === 'function') { - // @ts-expect-error _restore is added to be able to remove our monkey patched code - console[method]._restore() + if (typeof consoleWithRestore[method]._restore === 'function') { + consoleWithRestore[method]._restore() } }) + } } -const CONSOLE_LOG_METHODS: Array<'log' | 'debug' | 'info' | 'warn' | 'error'> = filter( +const CONSOLE_LOG_METHODS: ConsoleMethod[] = filter( ['log', 'debug', 'info', 'warn', 'error'], method => typeof console !== 'undefined' && typeof console[method] === 'function' From fbe391967a0d4a5b0a31244103ba803e9438741c Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Wed, 30 Oct 2024 12:28:19 +0000 Subject: [PATCH 6/6] fix: :adhesive_bandage: update types and exports --- packages/plugin-console-breadcrumbs/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/plugin-console-breadcrumbs/package.json b/packages/plugin-console-breadcrumbs/package.json index 9c9d52f414..41d5c4e47c 100644 --- a/packages/plugin-console-breadcrumbs/package.json +++ b/packages/plugin-console-breadcrumbs/package.json @@ -2,12 +2,12 @@ "name": "@bugsnag/plugin-console-breadcrumbs", "version": "8.1.1", "main": "dist/console-breadcrumbs.js", - "types": "dist/types/throttle.d.ts", + "types": "dist/types/console-breadcrumbs.d.ts", "exports": { ".": { - "types": "./dist/types/throttle.d.ts", - "default": "./dist/throttle.js", - "import": "./dist/throttle.mjs" + "types": "./dist/types/console-breadcrumbs.d.ts", + "default": "./dist/console-breadcrumbs.js", + "import": "./dist/console-breadcrumbs.mjs" } }, "description": "@bugsnag/js plugin to record console log method calls as breadcrumbs",