From eb041fafb6a53a5bf783f3c2f613202da30df27c Mon Sep 17 00:00:00 2001 From: Willy Brauner Date: Sun, 13 Apr 2025 23:50:31 +0200 Subject: [PATCH] feat: Add elapsed time --- examples/browser/package.json | 6 -- examples/browser/src/index.ts | 32 ++++++++-- examples/browser/tsconfig.json | 21 +------ package.json | 3 +- src/debug.ts | 110 +++++++++++++++++++++++---------- test/debug.test.ts | 3 +- 6 files changed, 110 insertions(+), 65 deletions(-) diff --git a/examples/browser/package.json b/examples/browser/package.json index 317c088..a144266 100644 --- a/examples/browser/package.json +++ b/examples/browser/package.json @@ -1,15 +1,9 @@ { "name": "browser", - "version": "1.0.0", - "description": "", - "main": "index.js", "scripts": { "dev": "vite --host", "build": "vite build" }, - "keywords": [], - "author": "", - "license": "ISC", "dependencies": { "@wbe/debug": "workspace:*" }, diff --git a/examples/browser/src/index.ts b/examples/browser/src/index.ts index a58e54b..7e9055a 100644 --- a/examples/browser/src/index.ts +++ b/examples/browser/src/index.ts @@ -1,10 +1,32 @@ import { menu } from "./Menu" import debug, { couleur } from "@wbe/debug" +;(async () => { + const log = debug("front:index") + log("index log", { props: "foo" }) -const log = debug("front:index") + for (let i = 0; i < 10; i++) { + await new Promise((resolve) => + setTimeout(resolve, 100 * Math.random() + 100 / 100) + ) + debug(`front:${i + "-test"}`)(`index log ${i}`) + } + debug(`front:others-types`)( + `new log`, + [ + { name: "foo", value: "bar" }, + { name: "bar", value: "foo" }, + { name: "baz", value: "qux" }, + { name: "qux", value: "baz" }, + ], + null, + undefined, + "foo" + ) + menu() -log("index log", { props: "foo" }) -log("test 2") + console.log("native console log (should be removed by esbuild in production)") -console.log(couleur.bold("native console log: hello bold")) -menu() + for (let i = 0; i < 3; i++) { + console.log("native console log", i) + } +})() diff --git a/examples/browser/tsconfig.json b/examples/browser/tsconfig.json index 3ade32b..0d5ccc8 100644 --- a/examples/browser/tsconfig.json +++ b/examples/browser/tsconfig.json @@ -1,29 +1,10 @@ { "compilerOptions": { - "module": "commonjs", + "module": "esnext", "target": "esnext", - "outDir": "dist", - "rootDir": "../../", - "composite": false, - "lib": ["dom", "es2015"], "moduleResolution": "node", "types": ["node"], - "declaration": true, - "noImplicitAny": false, - "esModuleInterop": true, - "preserveConstEnums": true, - "strictNullChecks": false, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "sourceMap": true, - "resolveJsonModule": true, - "noEmit": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true }, - "include": ["./","../../dist"] } diff --git a/package.json b/package.json index b529a6d..e7b4b2e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "import": "./dist/index.js" } }, + "types": "./dist/index.d.ts", "sideEffects": false, "repository": { "type": "git", @@ -56,7 +57,7 @@ { "name": "@wbe/debug", "path": "dist/index.js", - "limit": "500 B" + "limit": "600 B" } ], "packageManager": "pnpm@9.14.2+sha512.6e2baf77d06b9362294152c851c4f278ede37ab1eba3a55fda317a4a17b209f4dbb973fb250a77abc463a341fcb1f17f17cfa24091c4eb319cda0d9b84278387" diff --git a/src/debug.ts b/src/debug.ts index 0fe183d..12b3458 100644 --- a/src/debug.ts +++ b/src/debug.ts @@ -1,39 +1,85 @@ import { couleur } from "./couleur" import { isBrowser, stringToRgb } from "./helpers" +let LAST_TIME = Date.now() + /** * debug + * @param namespace - The namespace to log + * @returns A function that logs the namespace and arguments to the console + * + * ex: + * import debug from "@wbe/debug" + * const log = debug("myNamespace") + * log("Hello World") // logs "myNamespace Hello World +0ms" */ -// prettier-ignore -export const debug = (namespace?: string) => (...rest: any[]): void => { - const rgb = stringToRgb(namespace) - - const showLog = (value: string): boolean => - value?.includes(":*") - ? namespace.startsWith( value.split(":*")[0]) - : value === namespace || value === "*" - - // Allow to bypass dropping of console.log from the build process - // tested with esbuild config: pure: ["console.log"] or drop: ["console"] - const log = console['log'] - - if (isBrowser) - { - showLog(localStorage.getItem("debug")) - && - log( - namespace && `%c${namespace}`, `color: rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`, - ...rest - ) - } - - else -{ - showLog(process.env.DEBUG) - && - log( - namespace && couleur.bold(couleur.rgb(rgb[0], rgb[1], rgb[2])(namespace)), - ...rest - ) +export const debug = + (namespace?: string, elapsedTime = true) => + (...rest: any[]): void => { + // Calculate elapsed time since last execution + const now = Date.now() + const elapsed = now - LAST_TIME + LAST_TIME = now + const elapsedString = `+${elapsed}ms` + + // Get the namespace color + const rgb = stringToRgb(namespace) + + // Define when to show the log + const showLog = (value: string): boolean => + value?.includes(":*") + ? namespace.startsWith(value.split(":*")[0]) + : value === namespace || value === "*" + + // Allow to bypass dropping of console.log from the build process + // has been test with esbuild drop: ["console"] & pure: ["console.log"] + const log = console["log"] + + /** + * Browser environment + */ + if (isBrowser) { + if (showLog(localStorage.getItem("debug"))) { + const colorStyle = `color: rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]}); font-weight: bold` + const args = [] + + // Start with the colored namespace format specifier and its style + let format = `%c${namespace}` + args.push(colorStyle) + + // Process the rest arguments + // Use %c for strings to allow potential future styling or just display + // Use %o for objects, arrays, etc., for better inspection + for (let i = 0; i < rest.length; i++) { + const arg = rest[i] + if (typeof arg === "string") { + format += ` %c${arg}` + args.push("color: inherit") + } else { + format += " %o" + args.push(arg) + } + } + // Append the elapsed time format specifier and its style + if (elapsedTime) { + format += ` %c${elapsedString}` + args.push(colorStyle) + } + // Append the whole formatted string and log it + args.unshift(format) + log(...args) + } + } else { + /** + * Node.js environment + */ + const wColor = (s: string) => + couleur.bold(couleur.rgb(rgb[0], rgb[1], rgb[2])(s)) + + if (showLog(process.env.DEBUG)) { + elapsedTime + ? log(wColor(namespace), ...rest, wColor(elapsedString)) + : log(wColor(namespace), ...rest) + } + } } -} diff --git a/test/debug.test.ts b/test/debug.test.ts index a13e81f..4cf443d 100644 --- a/test/debug.test.ts +++ b/test/debug.test.ts @@ -77,7 +77,8 @@ describe("debug", () => { expect(consoleLogCalls.length).toBe(1) }) - it("should log multiple arguments correctly", () => { + it("should log multiple arguments correctly", async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)) process.env.DEBUG = "test-namespace" const testDebug = debug("test-namespace") testDebug("First argument", "Second argument", { key: "value" }, 123)