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. ![](https://img.shields.io/npm/v/@wbe/debug/latest.svg) ![](https://github.com/willybrauner/debug/workflows/CI/badge.svg) 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"