diff --git a/README.md b/README.md
index 0a45c1a..54df0c3 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# @wbe/debug
-Tiny debug tool (~500 bytes) for terminal and browser inspired by [debug-js/debug](https://github.com/debug-js/debug) API.
+Tiny debug tool (~600 bytes) for terminal and browser inspired by [debug-js/debug](https://github.com/debug-js/debug) API.


diff --git a/bench/bench-browser/.gitignore b/bench/bench-browser/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/bench/bench-browser/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/bench/bench-browser/index.html b/bench/bench-browser/index.html
new file mode 100644
index 0000000..1f29684
--- /dev/null
+++ b/bench/bench-browser/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ @wbe/debug vs debug - Benchmark
+
+
+
+
+
+
+
diff --git a/bench/bench-browser/package.json b/bench/bench-browser/package.json
new file mode 100644
index 0000000..e100fa5
--- /dev/null
+++ b/bench/bench-browser/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "browser-bench",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@wbe/debug": "workspace:*",
+ "debug": "4.4.0",
+ "preact": "^10.26.5"
+ },
+ "devDependencies": {
+ "sass": "^1.86.3",
+ "typescript": "~5.7.2",
+ "vite": "^6.2.0"
+ }
+}
diff --git a/bench/bench-browser/public/vite.svg b/bench/bench-browser/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/bench/bench-browser/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/bench/bench-browser/src/App.tsx b/bench/bench-browser/src/App.tsx
new file mode 100644
index 0000000..345dd5d
--- /dev/null
+++ b/bench/bench-browser/src/App.tsx
@@ -0,0 +1,277 @@
+import { useState, useEffect } from "preact/hooks"
+import debugOriginal from "debug"
+import debugWbe from "@wbe/debug"
+
+interface BenchmarkResults {
+ debugOriginal: number
+ debugWbe: number
+ iterations: number
+ testMessages: any[]
+ completed: boolean
+}
+
+export const BenchmarkApp = () => {
+ const [results, setResults] = useState({
+ debugOriginal: 0,
+ debugWbe: 0,
+ iterations: 10000,
+ testMessages: [],
+ completed: false,
+ })
+ const [isRunning, setIsRunning] = useState(false)
+
+ useEffect(() => {
+ runBenchmark()
+ }, [])
+
+ const runBenchmark = async () => {
+ setIsRunning(true)
+
+ const logBench = debugWbe("bench:main")
+ logBench("Starting browser benchmark...")
+
+ // Setup for benchmarking
+ const iterations = results.iterations
+ const benchResults = {
+ debugOriginal: 0,
+ debugWbe: 0,
+ }
+
+ // Create loggers for each library
+ const logOriginal = debugOriginal("bench:original")
+ const logWbe = debugWbe("bench:wbe")
+
+ // Warmup phase - warm up both libraries more thoroughly
+ logBench("Warming up...")
+ for (let i = 0; i < 1000; i++) {
+ logOriginal("warmup")
+ logWbe("warmup")
+ }
+
+ // Setup test messages with different complexity
+ const testMessages = [
+ "Simple string message",
+ ["Array", "of", "strings"],
+ { complex: "object", with: { nested: "properties" } },
+ ["Mixed", 123, { type: "content" }],
+ ]
+
+ // Update state with test messages
+ setResults((prev) => ({ ...prev, testMessages }))
+
+ // Run multiple rounds of benchmarking in alternating order
+ const numberOfRounds = 4
+ const roundResults = {
+ debugOriginal: [] as number[],
+ debugWbe: [] as number[],
+ }
+
+ logBench(
+ `Running ${numberOfRounds} rounds of benchmarks in alternating order...`
+ )
+
+ for (let round = 0; round < numberOfRounds; round++) {
+ logBench(`Round ${round + 1}/${numberOfRounds}`)
+
+ // Determine order based on round number (alternate)
+ const runFirstSecond =
+ round % 2 === 0
+ ? [runOriginalBenchmark, runWbeBenchmark]
+ : [runWbeBenchmark, runOriginalBenchmark]
+
+ // Run benchmarks in determined order
+ await new Promise((resolve) => setTimeout(resolve, 100)) // Small pause between rounds
+ const result1 = await runFirstSecond[0]()
+ await new Promise((resolve) => setTimeout(resolve, 100)) // Small pause between tests
+ const result2 = await runFirstSecond[1]()
+
+ // Store results in correct slots regardless of execution order
+ if (round % 2 === 0) {
+ roundResults.debugOriginal.push(result1)
+ roundResults.debugWbe.push(result2)
+ } else {
+ roundResults.debugWbe.push(result1)
+ roundResults.debugOriginal.push(result2)
+ }
+ }
+
+ // Calculate average results
+ benchResults.debugOriginal =
+ roundResults.debugOriginal.reduce((a, b) => a + b, 0) / numberOfRounds
+ benchResults.debugWbe =
+ roundResults.debugWbe.reduce((a, b) => a + b, 0) / numberOfRounds
+
+ logBench("All benchmark rounds completed.")
+
+ // Function to benchmark original debug
+ async function runOriginalBenchmark() {
+ logBench("Benchmarking original debug library...")
+ const start = performance.now()
+
+ for (let i = 0; i < iterations; i++) {
+ const msgIndex = i % testMessages.length
+ logOriginal(testMessages[msgIndex])
+ }
+
+ const duration = performance.now() - start
+ logBench(`Original debug completed in ${duration.toFixed(2)}ms`)
+ return duration
+ }
+
+ // Function to benchmark @wbe/debug
+ async function runWbeBenchmark() {
+ logBench("Benchmarking @wbe/debug library...")
+ const start = performance.now()
+
+ for (let i = 0; i < iterations; i++) {
+ const msgIndex = i % testMessages.length
+ logWbe(testMessages[msgIndex])
+ }
+
+ const duration = performance.now() - start
+ logBench(`@wbe/debug completed in ${duration.toFixed(2)}ms`)
+ return duration
+ }
+
+ // Display results
+ logBench("Browser benchmark completed.")
+
+ console.log(
+ "%c---- BENCHMARK RESULTS ----",
+ "font-weight: bold; font-size: 16px;"
+ )
+ console.log(`Total iterations per library: ${iterations}`)
+ console.log(
+ `Original debug: ${benchResults.debugOriginal.toFixed(2)}ms (${(
+ benchResults.debugOriginal / iterations
+ ).toFixed(3)}ms per call)`
+ )
+ console.log(
+ `@wbe/debug: ${benchResults.debugWbe.toFixed(2)}ms (${(
+ benchResults.debugWbe / iterations
+ ).toFixed(3)}ms per call)`
+ )
+ console.log(
+ `Difference: ${(
+ benchResults.debugWbe - benchResults.debugOriginal
+ ).toFixed(2)}ms`
+ )
+
+ if (benchResults.debugWbe < benchResults.debugOriginal) {
+ console.log(
+ `%c@wbe/debug is ${(
+ (benchResults.debugOriginal / benchResults.debugWbe - 1) *
+ 100
+ ).toFixed(2)}% faster`,
+ "color: green; font-weight: bold"
+ )
+ } else {
+ console.log(
+ `%cOriginal debug is ${(
+ (benchResults.debugWbe / benchResults.debugOriginal - 1) *
+ 100
+ ).toFixed(2)}% faster`,
+ "color: red; font-weight: bold"
+ )
+ }
+
+ // Update state with results
+ setResults({
+ debugOriginal: benchResults.debugOriginal,
+ debugWbe: benchResults.debugWbe,
+ iterations,
+ testMessages,
+ completed: true,
+ })
+
+ setIsRunning(false)
+ }
+
+ return (
+
+
+
+
+
+ {results.completed &&
}
+
+ )
+}
+
+const BenchmarkResults = ({ results }: { results: BenchmarkResults }) => {
+ const { debugOriginal, debugWbe, iterations, testMessages } = results
+
+ const originalPerCall = debugOriginal / iterations
+ const wbePerCall = debugWbe / iterations
+ const difference = debugWbe - debugOriginal
+
+ // Calculate percentage difference
+ const isWbeFaster = debugWbe < debugOriginal
+ const percentDiff = isWbeFaster
+ ? ((debugOriginal / debugWbe - 1) * 100).toFixed(2)
+ : ((debugWbe / debugOriginal - 1) * 100).toFixed(2)
+
+ // Calculate bar widths
+ const maxTime = Math.max(debugOriginal, debugWbe)
+ const originalBarWidth = `${Math.min(100, (debugOriginal / maxTime) * 100)}%`
+ const wbeBarWidth = `${Math.min(100, (debugWbe / maxTime) * 100)}%`
+
+ return (
+
+
Benchmark Results
+
+
+
+ Total iterations per library: {iterations}
+
+
+
+ {isWbeFaster
+ ? `@wbe/debug is ${percentDiff}% faster`
+ : `Original debug is ${percentDiff}% faster`}
+
+
+
+
+
+
+
+ Original debug: {debugOriginal.toFixed(2)}ms (
+ {originalPerCall.toFixed(3)}ms per call)
+
+
+ {originalPerCall.toFixed(3)}ms
+
+
+
+
+
+ @wbe/debug: {debugWbe.toFixed(2)}ms ({wbePerCall.toFixed(3)}ms per
+ call)
+
+
+ {wbePerCall.toFixed(3)}ms
+
+
+
+
+
+
Difference: {difference.toFixed(2)}ms
+
+
+
+
Test Details
+
+ - Iterations: {iterations}
+ - Test performed on: {new Date().toLocaleString()}
+ - Browser: {navigator.userAgent}
+
+
+
Test Messages
+
{JSON.stringify(testMessages, null, 2)}
+
+
+ )
+}
diff --git a/bench/bench-browser/src/main.tsx b/bench/bench-browser/src/main.tsx
new file mode 100644
index 0000000..4be3d09
--- /dev/null
+++ b/bench/bench-browser/src/main.tsx
@@ -0,0 +1,8 @@
+import { render } from "preact"
+import { BenchmarkApp } from "./App"
+import "./styles/main.scss"
+
+localStorage.setItem("debug", "*")
+;(() => {
+ render(, document.getElementById("app")!)
+})()
diff --git a/bench/bench-browser/src/styles/main.scss b/bench/bench-browser/src/styles/main.scss
new file mode 100644
index 0000000..d02226f
--- /dev/null
+++ b/bench/bench-browser/src/styles/main.scss
@@ -0,0 +1,159 @@
+// Variables
+$primary-color: #4caf50;
+$primary-hover-color: #45a049;
+$secondary-color: #3498db;
+$accent-color: #2ecc71;
+$text-color: #333;
+$text-secondary: #666;
+$border-color: #ddd;
+$bg-light: #f8f9fa;
+$bg-white: #fff;
+$bg-disabled: #cccccc;
+
+// Base styles
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+ line-height: 1.6;
+ margin: 0;
+ padding: 0;
+ color: $text-color;
+}
+
+#app {
+ max-width: 1000px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+// Header
+.header {
+ text-align: center;
+ margin-bottom: 30px;
+
+ h1 {
+ margin-bottom: 10px;
+ }
+}
+
+.description {
+ color: $text-secondary;
+ font-size: 18px;
+}
+
+// Console output section
+.console-output {
+ background-color: $bg-light;
+ border-radius: 4px;
+ padding: 15px;
+ margin-bottom: 30px;
+ border: 1px solid $border-color;
+ overflow: auto;
+ max-height: 300px;
+
+ h2 {
+ margin-top: 0;
+ }
+}
+
+pre {
+ background-color: $bg-light;
+ border-radius: 4px;
+ padding: 10px;
+ overflow: auto;
+}
+
+// Benchmark components
+.loading {
+ padding: 20px;
+ background-color: $bg-light;
+ border-radius: 4px;
+ text-align: center;
+ margin-bottom: 20px;
+ font-weight: bold;
+}
+
+.results {
+ padding: 20px;
+ background-color: $bg-white;
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+ margin-bottom: 30px;
+}
+
+.summary {
+ margin-bottom: 20px;
+ padding: 15px;
+ background-color: $bg-light;
+ border-radius: 4px;
+}
+
+.winner {
+ font-size: 18px;
+}
+
+// Bars for visualizing results
+.result-bars {
+ margin-bottom: 20px;
+}
+
+.bar-container {
+ margin-bottom: 20px;
+}
+
+.bar-label {
+ margin-bottom: 5px;
+}
+
+.bar {
+ height: 30px;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ padding-left: 10px;
+ color: white;
+ font-weight: bold;
+ transition: width 1s;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+
+ &.original-bar {
+ background-color: $secondary-color;
+ }
+
+ &.wbe-bar {
+ background-color: $accent-color;
+ }
+}
+
+// Test details section
+.test-details {
+ margin-top: 30px;
+ padding: 15px;
+ background-color: $bg-light;
+ border-radius: 4px;
+}
+
+// Action buttons
+.actions {
+ margin-top: 20px;
+ text-align: center;
+}
+
+.run-btn {
+ padding: 10px 20px;
+ background-color: $primary-color;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 16px;
+ transition: background-color 0.3s;
+
+ &:hover {
+ background-color: $primary-hover-color;
+ }
+
+ &:disabled {
+ background-color: $bg-disabled;
+ cursor: not-allowed;
+ }
+}
\ No newline at end of file
diff --git a/bench/bench-browser/src/vite-env.d.ts b/bench/bench-browser/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/bench/bench-browser/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/bench/bench-browser/tsconfig.json b/bench/bench-browser/tsconfig.json
new file mode 100644
index 0000000..025c48e
--- /dev/null
+++ b/bench/bench-browser/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* JSX Support for Preact */
+ "jsx": "react-jsx",
+ "jsxImportSource": "preact",
+
+ /* Linting */
+ "strict": false,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["src"],
+
+}
diff --git a/bench/bench-node/package.json b/bench/bench-node/package.json
new file mode 100644
index 0000000..2fbd1f5
--- /dev/null
+++ b/bench/bench-node/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "bench-node",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "start": "tsx src/index.ts",
+ "build": "tsc"
+ },
+ "dependencies": {
+ "@wbe/debug": "workspace:*",
+ "debug": "4.4.0",
+ "chalk": "^5.3.0"
+ },
+ "devDependencies": {
+ "typescript": "~5.7.2",
+ "tsx": "^4.7.0"
+ }
+}
diff --git a/bench/bench-node/src/index.ts b/bench/bench-node/src/index.ts
new file mode 100644
index 0000000..48fd5bc
--- /dev/null
+++ b/bench/bench-node/src/index.ts
@@ -0,0 +1,239 @@
+import debugOriginal from "debug"
+import debugWbe from "@wbe/debug"
+import chalk from "chalk"
+
+// Enable logs for both libraries but redirect to null
+// This allows the libraries to run their code paths but without the I/O overhead
+process.env.DEBUG = "*"
+
+// Redirect console output during benchmarking
+const originalConsoleLog = console.log
+const disableConsoleOutput = () => {
+ console.log = () => {}
+}
+const restoreConsoleOutput = () => {
+ console.log = originalConsoleLog
+}
+
+// Function to format numbers with commas for better readability
+const formatNumber = (num: number): string => {
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
+}
+
+/**
+ * Benchmark class to compare @wbe/debug vs debug performances
+ */
+class Benchmark {
+ private readonly iterations: number
+ private readonly warmupIterations: number
+ private results: {
+ debugOriginal: number
+ debugWbe: number
+ }
+ private testMessages: any[]
+
+ constructor(iterations: number = 100000, warmupIterations: number = 1000) {
+ this.iterations = iterations
+ this.warmupIterations = warmupIterations
+ this.results = {
+ debugOriginal: 0,
+ debugWbe: 0,
+ }
+
+ // Create a variety of test messages to use in benchmarks
+ this.testMessages = [
+ "Simple string message",
+ ["Array", "of", "strings"],
+ { complex: "object", with: { nested: "properties" } },
+ ["Mixed", 123, { type: "content" }],
+ ]
+ }
+
+ /**
+ * Run warmup phase to initialize both libraries
+ */
+ private warmup(): void {
+ console.log(chalk.dim("Warming up..."))
+
+ const logOriginal = debugOriginal("bench:original:warmup")
+ const logWbe = debugWbe("bench:wbe:warmup")
+
+ disableConsoleOutput()
+ for (let i = 0; i < this.warmupIterations; i++) {
+ logOriginal("warmup")
+ logWbe("warmup")
+ }
+ restoreConsoleOutput()
+ }
+
+ /**
+ * Benchmark the original debug library
+ */
+ private benchmarkOriginal(): void {
+ console.log(
+ chalk.blue.bold(
+ `\nBenchmarking ${chalk.underline("original debug")} library...`
+ )
+ )
+
+ const logOriginal = debugOriginal("bench:original")
+
+ disableConsoleOutput()
+ const start = process.hrtime.bigint()
+
+ for (let i = 0; i < this.iterations; i++) {
+ const msgIndex = i % this.testMessages.length
+ logOriginal(this.testMessages[msgIndex])
+ }
+
+ const end = process.hrtime.bigint()
+ restoreConsoleOutput()
+
+ this.results.debugOriginal = Number(end - start) / 1_000_000 // Convert to ms
+ }
+
+ /**
+ * Benchmark the @wbe/debug library
+ */
+ private benchmarkWbe(): void {
+ console.log(
+ chalk.green.bold(
+ `\nBenchmarking ${chalk.underline("@wbe/debug")} library...`
+ )
+ )
+
+ const logWbe = debugWbe("bench:wbe")
+
+ disableConsoleOutput()
+ const start = process.hrtime.bigint()
+
+ for (let i = 0; i < this.iterations; i++) {
+ const msgIndex = i % this.testMessages.length
+ logWbe(this.testMessages[msgIndex])
+ }
+
+ const end = process.hrtime.bigint()
+ restoreConsoleOutput()
+
+ this.results.debugWbe = Number(end - start) / 1_000_000 // Convert to ms
+ }
+
+ /**
+ * Display the benchmark results
+ */
+ private displayResults(): void {
+ console.log("\n" + chalk.yellow.bold("=".repeat(50)))
+ console.log(chalk.yellow.bold(" BENCHMARK RESULTS"))
+ console.log(chalk.yellow.bold("=".repeat(50)) + "\n")
+
+ const { debugOriginal, debugWbe } = this.results
+
+ console.log(
+ `Total iterations per library: ${chalk.bold(
+ formatNumber(this.iterations)
+ )}`
+ )
+ console.log(
+ `Test messages: ${chalk.dim(JSON.stringify(this.testMessages))}\n`
+ )
+
+ // Calculate per-operation times
+ const originalPerOp = debugOriginal / this.iterations
+ const wbePerOp = debugWbe / this.iterations
+
+ // Display the results for the original debug library
+ console.log(chalk.blue.bold("Original debug:"))
+ console.log(` Total time: ${chalk.bold(debugOriginal.toFixed(2) + " ms")}`)
+ console.log(
+ ` Per operation: ${chalk.bold(originalPerOp.toFixed(6) + " ms")}\n`
+ )
+
+ // Display the results for @wbe/debug
+ console.log(chalk.green.bold("@wbe/debug:"))
+ console.log(` Total time: ${chalk.bold(debugWbe.toFixed(2) + " ms")}`)
+ console.log(` Per operation: ${chalk.bold(wbePerOp.toFixed(6) + " ms")}\n`)
+
+ // Display the difference
+ const diff = debugWbe - debugOriginal
+ console.log(
+ `Absolute difference: ${chalk.bold(Math.abs(diff).toFixed(2) + " ms")}`
+ )
+
+ // Calculate which one is faster
+ if (debugWbe < debugOriginal) {
+ const percentFaster = ((debugOriginal / debugWbe - 1) * 100).toFixed(2)
+ console.log(
+ chalk.green.bold(
+ `@wbe/debug is ${percentFaster}% faster than original debug`
+ )
+ )
+ } else {
+ const percentFaster = ((debugWbe / debugOriginal - 1) * 100).toFixed(2)
+ console.log(
+ chalk.blue.bold(
+ `Original debug is ${percentFaster}% faster than @wbe/debug`
+ )
+ )
+ }
+
+ // Display a simple visualization of the results
+ this.displayVisualization()
+ }
+
+ /**
+ * Display a simple ASCII visualization of the benchmark results
+ */
+ private displayVisualization(): void {
+ const { debugOriginal, debugWbe } = this.results
+ const maxTime = Math.max(debugOriginal, debugWbe)
+
+ // Calculate bar lengths (max 40 chars)
+ const maxBarLength = 40
+ const originalBarLength = Math.round(
+ (debugOriginal / maxTime) * maxBarLength
+ )
+ const wbeBarLength = Math.round((debugWbe / maxTime) * maxBarLength)
+
+ console.log("\n" + chalk.yellow.bold("Performance Comparison:"))
+
+ // Original debug bar
+ process.stdout.write(chalk.blue.bold("Original debug: "))
+ process.stdout.write(chalk.blue("ā".repeat(originalBarLength)))
+ console.log(` ${debugOriginal.toFixed(2)} ms`)
+
+ // @wbe/debug bar
+ process.stdout.write(chalk.green.bold("@wbe/debug: "))
+ process.stdout.write(chalk.green("ā".repeat(wbeBarLength)))
+ console.log(` ${debugWbe.toFixed(2)} ms`)
+
+ console.log("\n" + chalk.yellow.bold("=".repeat(50)))
+ }
+
+ /**
+ * Run the complete benchmark
+ */
+ public async run(): Promise {
+ console.log(
+ chalk.bold("\nš Starting Node.js benchmark: @wbe/debug vs debug")
+ )
+ console.log(
+ chalk.dim(`Running with ${formatNumber(this.iterations)} iterations`)
+ )
+
+ // First warm up
+ this.warmup()
+
+ // Benchmark original debug
+ this.benchmarkOriginal()
+
+ // Benchmark @wbe/debug
+ this.benchmarkWbe()
+
+ // Display results
+ this.displayResults()
+ }
+}
+
+// Run the benchmark with 100,000 iterations
+const benchmark = new Benchmark(100000)
+benchmark.run().catch(console.error)
diff --git a/bench/bench-node/tsconfig.json b/bench/bench-node/tsconfig.json
new file mode 100644
index 0000000..b5ac89a
--- /dev/null
+++ b/bench/bench-node/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "esModuleInterop": true,
+ "strict": true,
+ "outDir": "dist",
+ "skipLibCheck": true
+ },
+ "include": ["src"]
+}
\ No newline at end of file
diff --git a/examples/browser/package.json b/examples/browser/package.json
index a144266..e4897b1 100644
--- a/examples/browser/package.json
+++ b/examples/browser/package.json
@@ -5,7 +5,8 @@
"build": "vite build"
},
"dependencies": {
- "@wbe/debug": "workspace:*"
+ "@wbe/debug": "workspace:*",
+ "debug": "latest"
},
"devDependencies": {
"vite": "^6.2.6"
diff --git a/examples/browser/src/Menu.ts b/examples/browser/src/Menu.ts
deleted file mode 100644
index 938e66e..0000000
--- a/examples/browser/src/Menu.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import debug from "@wbe/debug"
-const log = debug("front:menu")
-export const menu = () => {
- log("Menu log", {test: "foo"}, "bar");
-}
diff --git a/examples/browser/src/index.ts b/examples/browser/src/index.ts
index 7e9055a..ee9b792 100644
--- a/examples/browser/src/index.ts
+++ b/examples/browser/src/index.ts
@@ -1,16 +1,23 @@
-import { menu } from "./Menu"
-import debug, { couleur } from "@wbe/debug"
-;(async () => {
- const log = debug("front:index")
+import debug from "debug"
+import debugWbe from "@wbe/debug"
+
+const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
+
+const test = async (lib) => {
+ const log = lib("front:index")
log("index log", { props: "foo" })
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}`)
+ const log = lib(`front:${i}`)
+ await sleep(10)
+ log(`index log ${i}`)
+ await sleep(10)
+ log(`index log ${i}`)
+ await sleep(100)
+ log(`index log ${i}`)
}
- debug(`front:others-types`)(
+
+ lib(`front:others-types`)(
`new log`,
[
{ name: "foo", value: "bar" },
@@ -22,11 +29,17 @@ import debug, { couleur } from "@wbe/debug"
undefined,
"foo"
)
- menu()
console.log("native console log (should be removed by esbuild in production)")
for (let i = 0; i < 3; i++) {
console.log("native console log", i)
}
-})()
+}
+
+for (let lib of ["debug-js/debug", "@wbe/debug"]) {
+ console.log(
+ `--------------------------------------------------- ${lib} ---------------------------------------------------`
+ )
+ await test(lib === "debug-js/debug" ? debug : debugWbe)
+}
diff --git a/package.json b/package.json
index 1a27eb1..a7d15dd 100644
--- a/package.json
+++ b/package.json
@@ -57,7 +57,7 @@
{
"name": "@wbe/debug",
"path": "dist/index.js",
- "limit": "600 B"
+ "limit": "650 B"
}
],
"packageManager": "pnpm@9.14.2+sha512.6e2baf77d06b9362294152c851c4f278ede37ab1eba3a55fda317a4a17b209f4dbb973fb250a77abc463a341fcb1f17f17cfa24091c4eb319cda0d9b84278387"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e5a0932..90f05e1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -22,23 +22,67 @@ importers:
version: 5.39.0
tsup:
specifier: ^8.4.0
- version: 8.4.0(jiti@2.4.2)(postcss@8.5.3)(typescript@5.8.3)
+ version: 8.4.0(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.3)(typescript@5.8.3)
typescript:
specifier: ^5.8.3
version: 5.8.3
vitest:
specifier: ^3.1.1
- version: 3.1.1(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0)
+ version: 3.1.1(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3)
+
+ bench/bench-browser:
+ dependencies:
+ '@wbe/debug':
+ specifier: workspace:*
+ version: link:../..
+ debug:
+ specifier: 4.4.0
+ version: 4.4.0
+ preact:
+ specifier: ^10.26.5
+ version: 10.26.5
+ devDependencies:
+ sass:
+ specifier: ^1.86.3
+ version: 1.86.3
+ typescript:
+ specifier: ~5.7.2
+ version: 5.7.3
+ vite:
+ specifier: ^6.2.0
+ version: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3)
+
+ bench/bench-node:
+ dependencies:
+ '@wbe/debug':
+ specifier: workspace:*
+ version: link:../..
+ chalk:
+ specifier: ^5.3.0
+ version: 5.4.1
+ debug:
+ specifier: 4.4.0
+ version: 4.4.0
+ devDependencies:
+ tsx:
+ specifier: ^4.7.0
+ version: 4.19.3
+ typescript:
+ specifier: ~5.7.2
+ version: 5.7.3
examples/browser:
dependencies:
'@wbe/debug':
specifier: workspace:*
version: link:../..
+ debug:
+ specifier: latest
+ version: 4.4.0
devDependencies:
vite:
specifier: ^6.2.6
- version: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0)
+ version: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3)
examples/node:
dependencies:
@@ -226,6 +270,88 @@ packages:
'@jridgewell/trace-mapping@0.3.17':
resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==}
+ '@parcel/watcher-android-arm64@2.5.1':
+ resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher@2.5.1':
+ resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
+ engines: {node: '>= 10.0.0'}
+
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -416,6 +542,10 @@ packages:
brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
@@ -437,6 +567,10 @@ packages:
resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
engines: {node: '>=12'}
+ chalk@5.4.1:
+ resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
check-error@2.1.1:
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
engines: {node: '>= 16'}
@@ -480,6 +614,11 @@ packages:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
+ detect-libc@1.0.3:
+ resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -512,6 +651,10 @@ packages:
picomatch:
optional: true
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
@@ -526,14 +669,32 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
+ get-tsconfig@4.10.0:
+ resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==}
+
glob@10.4.5:
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
hasBin: true
+ immutable@5.1.1:
+ resolution: {integrity: sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -571,6 +732,10 @@ packages:
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
@@ -598,6 +763,9 @@ packages:
nanospinner@1.2.2:
resolution: {integrity: sha512-Zt/AmG6qRU3e+WnzGGLuMCEAO/dAu45stNbHY223tUxldaDAeE+FxSPsd9Q+j+paejmm0ZbrNVs5Sraqy3dRxA==}
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -623,6 +791,10 @@ packages:
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
picomatch@4.0.2:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
engines: {node: '>=12'}
@@ -653,6 +825,9 @@ packages:
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
engines: {node: ^10 || ^12 || >=14}
+ preact@10.26.5:
+ resolution: {integrity: sha512-fmpDkgfGU6JYux9teDWLhj9mKN55tyepwYbxHgQuIxbWQzgFg5vk7Mrrtfx7xRxq798ynkY4DDDxZr235Kk+4w==}
+
punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
@@ -665,11 +840,19 @@ packages:
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
engines: {node: '>=8'}
+ resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
rollup@4.40.0:
resolution: {integrity: sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
+ sass@1.86.3:
+ resolution: {integrity: sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -766,6 +949,10 @@ packages:
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
tr46@1.0.1:
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
@@ -795,6 +982,16 @@ packages:
typescript:
optional: true
+ tsx@4.19.3:
+ resolution: {integrity: sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==}
+ engines: {node: '>=18.0.0'}
+ hasBin: true
+
+ typescript@5.7.3:
+ resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
@@ -1010,6 +1207,67 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14
+ '@parcel/watcher-android-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher@2.5.1':
+ dependencies:
+ detect-libc: 1.0.3
+ is-glob: 4.0.3
+ micromatch: 4.0.8
+ node-addon-api: 7.1.1
+ optionalDependencies:
+ '@parcel/watcher-android-arm64': 2.5.1
+ '@parcel/watcher-darwin-arm64': 2.5.1
+ '@parcel/watcher-darwin-x64': 2.5.1
+ '@parcel/watcher-freebsd-x64': 2.5.1
+ '@parcel/watcher-linux-arm-glibc': 2.5.1
+ '@parcel/watcher-linux-arm-musl': 2.5.1
+ '@parcel/watcher-linux-arm64-glibc': 2.5.1
+ '@parcel/watcher-linux-arm64-musl': 2.5.1
+ '@parcel/watcher-linux-x64-glibc': 2.5.1
+ '@parcel/watcher-linux-x64-musl': 2.5.1
+ '@parcel/watcher-win32-arm64': 2.5.1
+ '@parcel/watcher-win32-ia32': 2.5.1
+ '@parcel/watcher-win32-x64': 2.5.1
+ optional: true
+
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -1102,13 +1360,13 @@ snapshots:
chai: 5.2.0
tinyrainbow: 2.0.0
- '@vitest/mocker@3.1.1(vite@6.2.6(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0))':
+ '@vitest/mocker@3.1.1(vite@6.2.6(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3))':
dependencies:
'@vitest/spy': 3.1.1
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
- vite: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0)
+ vite: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3)
'@vitest/pretty-format@3.1.1':
dependencies:
@@ -1157,6 +1415,11 @@ snapshots:
dependencies:
balanced-match: 1.0.2
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+ optional: true
+
buffer-from@1.1.2: {}
bundle-require@5.1.0(esbuild@0.25.2):
@@ -1176,6 +1439,8 @@ snapshots:
loupe: 3.1.3
pathval: 2.0.0
+ chalk@5.4.1: {}
+
check-error@2.1.1: {}
chokidar@4.0.3:
@@ -1206,6 +1471,9 @@ snapshots:
deep-eql@5.0.2: {}
+ detect-libc@1.0.3:
+ optional: true
+
eastasianwidth@0.2.0: {}
emoji-regex@8.0.0: {}
@@ -1252,6 +1520,11 @@ snapshots:
optionalDependencies:
picomatch: 4.0.2
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+ optional: true
+
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
@@ -1263,6 +1536,10 @@ snapshots:
fsevents@2.3.3:
optional: true
+ get-tsconfig@4.10.0:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
glob@10.4.5:
dependencies:
foreground-child: 3.3.1
@@ -1272,8 +1549,21 @@ snapshots:
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
+ immutable@5.1.1: {}
+
+ is-extglob@2.1.1:
+ optional: true
+
is-fullwidth-code-point@3.0.0: {}
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+ optional: true
+
+ is-number@7.0.0:
+ optional: true
+
isexe@2.0.0: {}
jackspeak@3.4.3:
@@ -1302,6 +1592,12 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+ optional: true
+
minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.1
@@ -1324,6 +1620,9 @@ snapshots:
dependencies:
picocolors: 1.1.1
+ node-addon-api@7.1.1:
+ optional: true
+
object-assign@4.1.1: {}
package-json-from-dist@1.0.1: {}
@@ -1341,16 +1640,20 @@ snapshots:
picocolors@1.1.1: {}
+ picomatch@2.3.1:
+ optional: true
+
picomatch@4.0.2: {}
pirates@4.0.6: {}
- postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3):
+ postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.3):
dependencies:
lilconfig: 3.1.3
optionalDependencies:
jiti: 2.4.2
postcss: 8.5.3
+ tsx: 4.19.3
postcss@8.5.3:
dependencies:
@@ -1358,12 +1661,16 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
+ preact@10.26.5: {}
+
punycode@2.3.0: {}
readdirp@4.1.2: {}
resolve-from@5.0.0: {}
+ resolve-pkg-maps@1.0.0: {}
+
rollup@4.40.0:
dependencies:
'@types/estree': 1.0.7
@@ -1390,6 +1697,14 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.40.0
fsevents: 2.3.2
+ sass@1.86.3:
+ dependencies:
+ chokidar: 4.0.3
+ immutable: 5.1.1
+ source-map-js: 1.2.1
+ optionalDependencies:
+ '@parcel/watcher': 2.5.1
+
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
@@ -1487,6 +1802,11 @@ snapshots:
tinyspy@3.0.2: {}
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+ optional: true
+
tr46@1.0.1:
dependencies:
punycode: 2.3.0
@@ -1495,7 +1815,7 @@ snapshots:
ts-interface-checker@0.1.13: {}
- tsup@8.4.0(jiti@2.4.2)(postcss@8.5.3)(typescript@5.8.3):
+ tsup@8.4.0(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.3)(typescript@5.8.3):
dependencies:
bundle-require: 5.1.0(esbuild@0.25.2)
cac: 6.7.14
@@ -1505,7 +1825,7 @@ snapshots:
esbuild: 0.25.2
joycon: 3.1.1
picocolors: 1.1.1
- postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.3)
+ postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.3)
resolve-from: 5.0.0
rollup: 4.40.0
source-map: 0.8.0-beta.0
@@ -1522,17 +1842,26 @@ snapshots:
- tsx
- yaml
+ tsx@4.19.3:
+ dependencies:
+ esbuild: 0.25.2
+ get-tsconfig: 4.10.0
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ typescript@5.7.3: {}
+
typescript@5.8.3: {}
undici-types@6.21.0: {}
- vite-node@3.1.1(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0):
+ vite-node@3.1.1(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3):
dependencies:
cac: 6.7.14
debug: 4.4.0
es-module-lexer: 1.6.0
pathe: 2.0.3
- vite: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0)
+ vite: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3)
transitivePeerDependencies:
- '@types/node'
- jiti
@@ -1547,7 +1876,7 @@ snapshots:
- tsx
- yaml
- vite@6.2.6(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0):
+ vite@6.2.6(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3):
dependencies:
esbuild: 0.25.2
postcss: 8.5.3
@@ -1556,12 +1885,14 @@ snapshots:
'@types/node': 22.14.1
fsevents: 2.3.3
jiti: 2.4.2
+ sass: 1.86.3
terser: 5.39.0
+ tsx: 4.19.3
- vitest@3.1.1(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0):
+ vitest@3.1.1(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3):
dependencies:
'@vitest/expect': 3.1.1
- '@vitest/mocker': 3.1.1(vite@6.2.6(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0))
+ '@vitest/mocker': 3.1.1(vite@6.2.6(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3))
'@vitest/pretty-format': 3.1.1
'@vitest/runner': 3.1.1
'@vitest/snapshot': 3.1.1
@@ -1577,8 +1908,8 @@ snapshots:
tinyexec: 0.3.2
tinypool: 1.0.2
tinyrainbow: 2.0.0
- vite: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0)
- vite-node: 3.1.1(@types/node@22.14.1)(jiti@2.4.2)(terser@5.39.0)
+ vite: 6.2.6(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3)
+ vite-node: 3.1.1(@types/node@22.14.1)(jiti@2.4.2)(sass@1.86.3)(terser@5.39.0)(tsx@4.19.3)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.14.1
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index c25addb..b939eef 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,2 +1,3 @@
packages:
- "examples/*"
+ - "bench/*"
diff --git a/src/couleur.ts b/src/couleur.ts
deleted file mode 100644
index 28c1487..0000000
--- a/src/couleur.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * couleur util API
- */
-function initCouleur() {
- const _close = "\u001B[39m"
-
- /**
- * Wrapper for ansi 256 code
- * @param code
- */
- const _wrapAnsi256 = (code) => `\u001B[${38};5;${code}m`
-
- /**
- * Convert RGB color to ansi 256
- * @param red
- * @param green
- * @param blue
- */
- const _rgbToAnsi256 = (red: number, green: number, blue: number): number => {
- if (red === green && green === blue) {
- if (red < 8) return 16
- if (red > 248) return 231
- return Math.round(((red - 8) / 247) * 24) + 232
- }
- return (
- 16 +
- 36 * Math.round((red / 255) * 5) +
- 6 * Math.round((green / 255) * 5) +
- Math.round((blue / 255) * 5)
- )
- }
-
- /**
- * Color string with rbg color
- * ex: couleur.rbg(255,0,0)('foo')
- */
- const rgb =
- (r: number, g: number, b: number) =>
- (str: string): string =>
- _wrapAnsi256(_rgbToAnsi256(r, g, b)) + str + _close
-
- /**
- * Bold text
- * @param str
- */
- const bold = (str: string): string => "\x1B[1m" + str + "\x1B[22m"
-
- return {
- rgb,
- bold,
- }
-}
-
-const couleur = initCouleur()
-export { couleur }
diff --git a/src/debug.ts b/src/debug.ts
index 12b3458..ea3fe54 100644
--- a/src/debug.ts
+++ b/src/debug.ts
@@ -1,35 +1,44 @@
-import { couleur } from "./couleur"
-import { isBrowser, stringToRgb } from "./helpers"
+import { ansiRgb, isBrowser, stringToRgb } from "./helpers"
-let LAST_TIME = Date.now()
+// Store timers per namespace instead of using a global timer
+let TIMERS: Record = {}
+
+// Maximum number of namespaces to track before cleanup
+const MAX_NAMESPACES = 1000
/**
* debug
* @param namespace - The namespace to log
+ * @param elapsedTime - Whether to show elapsed time since the last 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"
*/
-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`
+export const debug = (namespace?: string, elapsedTime = true) => {
+ const rgb = stringToRgb(namespace)
- // 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 === "*"
- // Define when to show the log
- const showLog = (value: string): boolean =>
- value?.includes(":*")
- ? namespace.startsWith(value.split(":*")[0])
- : value === namespace || value === "*"
+ return (...rest: any[]): void => {
+ // check if debug env exist in both environments
+ if (!showLog(isBrowser ? localStorage.getItem("debug") : process.env.DEBUG))
+ return
+
+ // Calculate elapsed time for each namespace to avoid global state & Cleanup if needed
+ const now = Date.now()
+ let elapsed = 0
+ if (TIMERS[namespace]) {
+ elapsed = now - TIMERS[namespace]
+ } else {
+ if (Object.keys(TIMERS).length >= MAX_NAMESPACES) {
+ TIMERS = {}
+ }
+ }
+ TIMERS[namespace] = now
+ const elapsedString =
+ elapsed > 1000 ? `+${Math.floor(elapsed / 1000)}s` : `+${elapsed}ms`
// Allow to bypass dropping of console.log from the build process
// has been test with esbuild drop: ["console"] & pure: ["console.log"]
@@ -39,47 +48,42 @@ export const debug =
* Browser environment
*/
if (isBrowser) {
- if (showLog(localStorage.getItem("debug"))) {
- const colorStyle = `color: rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]}); font-weight: bold`
- const args = []
+ const colorStyle = `color: rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]});`
+ 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)
- }
+ // 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)
}
+ // 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)
- }
+ const wColor = (s: string) => ansiRgb(rgb[0], rgb[1], rgb[2])(s)
+ const nspace = wColor(namespace)
+ elapsedTime
+ ? log(nspace, ...rest, wColor(elapsedString))
+ : log(nspace, ...rest)
}
}
+}
diff --git a/src/helpers.ts b/src/helpers.ts
index e2285df..73a6306 100644
--- a/src/helpers.ts
+++ b/src/helpers.ts
@@ -11,14 +11,63 @@ export const isBrowser: boolean = !!(
*/
export function stringToRgb(str: string): [number, number, number] {
if (!str) return [128, 128, 128]
+
+ // Add a salt to make numbers at the end produce different colors
+ const salt = 'x7f2q9';
+ const stringToHash = str + salt;
+
let hash = 0
- for (let i = 0; i < str.length; i++) {
- let character = str.charCodeAt(i)
+ for (let i = 0; i < stringToHash.length; i++) {
+ let character = stringToHash.charCodeAt(i)
hash = (hash << 5) - hash + character
hash = Math.abs(hash & hash)
}
+
+ // Create more variance in the RGB values
const r = (hash & 0xff0000) >> 16
- const g = (hash & 0x00ff00) >> 8
- const b = hash & 0x0000ff
+ const g = ((hash >> 3) & 0x00ff00) >> 8
+ const b = ((hash >> 6) & 0x0000ff)
+
return [r, g, b]
}
+
+/**
+ * ansi RGB
+ */
+export function ansiRgb(r: number, g: number, b: number) {
+ return function (str: string): string {
+ const _close = "\u001B[39m"
+
+ /**
+ * Wrapper for ansi 256 code
+ * @param code
+ */
+ const _wrapAnsi256 = (code) => `\u001B[${38};5;${code}m`
+
+ /**
+ * Convert RGB color to ansi 256
+ * @param red
+ * @param green
+ * @param blue
+ */
+ const _rgbToAnsi256 = (
+ red: number,
+ green: number,
+ blue: number
+ ): number => {
+ if (red === green && green === blue) {
+ if (red < 8) return 16
+ if (red > 248) return 231
+ return Math.round(((red - 8) / 247) * 24) + 232
+ }
+ return (
+ 16 +
+ 36 * Math.round((red / 255) * 5) +
+ 6 * Math.round((green / 255) * 5) +
+ Math.round((blue / 255) * 5)
+ )
+ }
+
+ return _wrapAnsi256(_rgbToAnsi256(r, g, b)) + str + _close
+ }
+}
diff --git a/src/index.ts b/src/index.ts
index eb5dc3f..5dfff75 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -10,4 +10,3 @@
*
*/
export { debug as default } from "./debug"
-export { couleur } from "./couleur"