@leftium/gg 0.0.33 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -36
- package/dist/GgConsole.svelte +12 -0
- package/dist/GgConsole.svelte.d.ts +4 -0
- package/dist/OpenInEditorLink.svelte +17 -7
- package/dist/OpenInEditorLink.svelte.d.ts +8 -2
- package/dist/debug/browser.d.ts +10 -0
- package/dist/debug/browser.js +102 -0
- package/dist/debug/common.d.ts +41 -0
- package/dist/debug/common.js +191 -0
- package/dist/debug/index.d.ts +9 -0
- package/dist/debug/index.js +11 -0
- package/dist/debug/node.d.ts +10 -0
- package/dist/debug/node.js +137 -0
- package/dist/eruda/loader.js +0 -11
- package/dist/eruda/plugin.js +310 -29
- package/dist/eruda/types.d.ts +11 -5
- package/dist/gg-call-sites-plugin.d.ts +84 -0
- package/dist/gg-call-sites-plugin.js +600 -165
- package/dist/gg.d.ts +80 -0
- package/dist/gg.js +459 -110
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/vite.d.ts +37 -0
- package/dist/vite.js +46 -0
- package/package.json +20 -12
- package/dist/debug-bundled.d.ts +0 -2
- package/dist/debug-bundled.js +0 -3
- package/dist/debug.d.ts +0 -2
- package/dist/debug.js +0 -15
- package/patches/debug@4.4.3.patch +0 -35
package/README.md
CHANGED
|
@@ -18,24 +18,101 @@
|
|
|
18
18
|
npm add @leftium/gg
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## SvelteKit Quick Start
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### 1. Use `gg()` anywhere
|
|
24
24
|
|
|
25
|
-
```
|
|
26
|
-
|
|
25
|
+
```svelte
|
|
26
|
+
<script>
|
|
27
|
+
import { gg } from '@leftium/gg';
|
|
28
|
+
|
|
29
|
+
gg('Hello world');
|
|
30
|
+
|
|
31
|
+
// Log expressions (returns first argument)
|
|
32
|
+
const result = gg(someFunction());
|
|
33
|
+
|
|
34
|
+
// Multiple arguments
|
|
35
|
+
gg('User:', user, 'Status:', status);
|
|
36
|
+
</script>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That's it! Output appears in the browser dev console and terminal. The following optional steps are highly recommended to unlock the full experience:
|
|
40
|
+
|
|
41
|
+
### 2. Add Vite plugins (optional, recommended)
|
|
42
|
+
|
|
43
|
+
Without plugins, namespaces are random word-tuples. With plugins, you get real file/function callpoints, open-in-editor links, and icecream-style source expressions.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// vite.config.ts
|
|
47
|
+
import ggPlugins from '@leftium/gg/vite';
|
|
48
|
+
import { sveltekit } from '@sveltejs/kit/vite';
|
|
49
|
+
import { defineConfig } from 'vite';
|
|
50
|
+
|
|
51
|
+
export default defineConfig({
|
|
52
|
+
plugins: [sveltekit(), ...ggPlugins()]
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`ggPlugins()` includes:
|
|
57
|
+
|
|
58
|
+
- **Call-sites plugin** -- rewrites `gg()` calls with source file/line/col metadata
|
|
59
|
+
- **Open-in-editor plugin** -- adds dev server middleware for click-to-open
|
|
60
|
+
- **Automatic `es2022` target** -- required for top-level await
|
|
61
|
+
|
|
62
|
+
### 3. Add the debug console (optional, recommended)
|
|
63
|
+
|
|
64
|
+
An in-browser debug console (powered by Eruda) with a dedicated GG tab for filtering and inspecting logs — especially useful on mobile.
|
|
65
|
+
|
|
66
|
+
```svelte
|
|
67
|
+
<!-- src/routes/+layout.svelte -->
|
|
68
|
+
<script>
|
|
69
|
+
import { GgConsole } from '@leftium/gg';
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<GgConsole />
|
|
73
|
+
{@render children()}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
In development, the debug console appears automatically.
|
|
77
|
+
In production, add `?gg` to the URL or use a 5-tap gesture to activate.
|
|
27
78
|
|
|
28
|
-
|
|
29
|
-
gg('Hello world');
|
|
79
|
+
## GgConsole Options
|
|
30
80
|
|
|
31
|
-
|
|
32
|
-
|
|
81
|
+
```svelte
|
|
82
|
+
<GgConsole prod={['url-param', 'gesture']} maxEntries={5000} />
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| Prop | Type | Default | Description |
|
|
86
|
+
| -------------- | -------------------------- | -------------------------- | ------------------------------ |
|
|
87
|
+
| `prod` | `Array \| string \| false` | `['url-param', 'gesture']` | Production activation triggers |
|
|
88
|
+
| `maxEntries` | `number` | `2000` | Max log entries in ring buffer |
|
|
89
|
+
| `erudaOptions` | `object` | `{}` | Pass-through options to Eruda |
|
|
90
|
+
|
|
91
|
+
**Production triggers:**
|
|
92
|
+
|
|
93
|
+
- `'url-param'` -- activate with `?gg` in the URL (persists to localStorage)
|
|
94
|
+
- `'gesture'` -- activate with 5 rapid taps anywhere on the page
|
|
95
|
+
- `'localStorage'` -- activate if `localStorage['gg-enabled']` is `'true'`
|
|
96
|
+
- `false` -- disable debug console in production entirely
|
|
97
|
+
|
|
98
|
+
## Vite Plugin Options
|
|
33
99
|
|
|
34
|
-
|
|
35
|
-
|
|
100
|
+
```ts
|
|
101
|
+
import ggPlugins from '@leftium/gg/vite';
|
|
102
|
+
|
|
103
|
+
ggPlugins({
|
|
104
|
+
callSites: { srcRootPattern: '.*?(/src/)' },
|
|
105
|
+
openInEditor: false // disable open-in-editor middleware
|
|
106
|
+
});
|
|
36
107
|
```
|
|
37
108
|
|
|
38
|
-
|
|
109
|
+
Individual plugins are also available for advanced setups:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { ggCallSitesPlugin, openInEditorPlugin } from '@leftium/gg/vite';
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Color Support (ANSI)
|
|
39
116
|
|
|
40
117
|
Color your logs for better visual distinction using `fg()` (foreground/text) and `bg()` (background):
|
|
41
118
|
|
|
@@ -77,46 +154,56 @@ gg(fg('rgb(255,99,71)')`Tomato text`);
|
|
|
77
154
|
|
|
78
155
|
**Where colors work:**
|
|
79
156
|
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
157
|
+
- Native browser console (Chrome DevTools, Firefox, etc.)
|
|
158
|
+
- GgConsole debug panel (mobile debugging)
|
|
159
|
+
- Node.js terminal
|
|
160
|
+
- All environments that support ANSI escape codes
|
|
84
161
|
|
|
85
|
-
##
|
|
162
|
+
## Other Frameworks
|
|
86
163
|
|
|
87
|
-
|
|
164
|
+
`gg()` works in any JavaScript project. The Vite plugins work with any Vite-based framework (React, Vue, Solid, etc.).
|
|
88
165
|
|
|
89
|
-
|
|
166
|
+
### Vanilla / Non-Svelte Setup
|
|
90
167
|
|
|
91
|
-
|
|
168
|
+
```ts
|
|
169
|
+
// vite.config.ts
|
|
170
|
+
import ggPlugins from '@leftium/gg/vite';
|
|
92
171
|
|
|
93
|
-
|
|
94
|
-
|
|
172
|
+
export default defineConfig({
|
|
173
|
+
plugins: [...ggPlugins()]
|
|
174
|
+
});
|
|
95
175
|
```
|
|
96
176
|
|
|
97
|
-
|
|
177
|
+
```js
|
|
178
|
+
// app.js
|
|
179
|
+
import { gg } from '@leftium/gg';
|
|
180
|
+
import { initGgEruda } from '@leftium/gg/eruda';
|
|
98
181
|
|
|
182
|
+
initGgEruda();
|
|
183
|
+
gg('works in any framework');
|
|
99
184
|
```
|
|
100
|
-
+123ms gg:routes/+page.svelte
|
|
101
|
-
```
|
|
102
185
|
|
|
103
|
-
|
|
186
|
+
## Technical Details
|
|
187
|
+
|
|
188
|
+
### Internal Debug Implementation
|
|
189
|
+
|
|
190
|
+
This library includes an **internal TypeScript implementation** inspired by the [`debug`](https://www.npmjs.com/package/debug) package. The output format displays time diffs **before** the namespace for better readability:
|
|
104
191
|
|
|
105
|
-
|
|
192
|
+
**Output format:**
|
|
106
193
|
|
|
107
|
-
|
|
194
|
+
```
|
|
195
|
+
+123ms gg:routes/+page.svelte
|
|
196
|
+
```
|
|
108
197
|
|
|
109
|
-
|
|
110
|
-
2. Update patch: `pnpm patch debug@x.x.x` (apply changes, then `pnpm patch-commit`)
|
|
111
|
-
3. Run the update script: `./scripts/update-debug.sh`
|
|
112
|
-
4. Verify patches are present: `git diff src/lib/debug/src/`
|
|
113
|
-
5. Test dev mode: `pnpm dev`
|
|
114
|
-
6. Test production build: `pnpm prepack`
|
|
115
|
-
7. Commit changes: `git commit -am "Update bundled debug to x.x.x"`
|
|
198
|
+
Features implemented internally (~290 lines of TypeScript):
|
|
116
199
|
|
|
117
|
-
|
|
200
|
+
- Color hashing algorithm for consistent namespace colors
|
|
201
|
+
- Millisecond diff formatting (e.g., `+123ms`, `+2s`, `+5m`)
|
|
202
|
+
- Namespace wildcard matching (`gg:*`, `gg:routes/*`, `-gg:test`)
|
|
203
|
+
- localStorage.debug / process.env.DEBUG persistence
|
|
204
|
+
- Browser and Node.js environments
|
|
118
205
|
|
|
119
|
-
|
|
206
|
+
This approach eliminates the need for vendoring, patching, and bundling third-party code, resulting in better type safety and simpler maintenance.
|
|
120
207
|
|
|
121
208
|
## Inspirations
|
|
122
209
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import type { GgErudaOptions } from './eruda/types.js';
|
|
4
|
+
|
|
5
|
+
let { prod, maxEntries, erudaOptions }: GgErudaOptions = $props();
|
|
6
|
+
|
|
7
|
+
onMount(() => {
|
|
8
|
+
import('./eruda/index.js').then(({ initGgEruda }) => {
|
|
9
|
+
initGgEruda({ prod, maxEntries, erudaOptions });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { dev } from '$app/environment';
|
|
3
3
|
|
|
4
|
+
type GgCallSiteInfo = { fileName: string; functionName: string; url: string };
|
|
5
|
+
|
|
4
6
|
let {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
gg,
|
|
8
|
+
url = gg?.url,
|
|
9
|
+
fileName = gg?.fileName,
|
|
10
|
+
title = gg ? `${gg.fileName}@${gg.functionName}` : fileName
|
|
11
|
+
}: {
|
|
12
|
+
gg?: GgCallSiteInfo;
|
|
13
|
+
url?: string;
|
|
14
|
+
fileName?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
} = $props();
|
|
9
17
|
|
|
10
18
|
// svelte-ignore non_reactive_update
|
|
11
19
|
let iframeElement: HTMLIFrameElement;
|
|
12
20
|
|
|
13
21
|
function onclick(event: MouseEvent) {
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
if (url) {
|
|
23
|
+
iframeElement.src = url;
|
|
24
|
+
event.preventDefault();
|
|
25
|
+
}
|
|
16
26
|
}
|
|
17
27
|
</script>
|
|
18
28
|
|
|
19
|
-
{#if dev}
|
|
29
|
+
{#if dev && fileName}
|
|
20
30
|
[📝<a {onclick} href={url} {title} target="_open-in-editor" class="open-in-editor-link">
|
|
21
31
|
{fileName}
|
|
22
32
|
</a>
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
type
|
|
2
|
-
url: string;
|
|
1
|
+
type GgCallSiteInfo = {
|
|
3
2
|
fileName: string;
|
|
3
|
+
functionName: string;
|
|
4
|
+
url: string;
|
|
5
|
+
};
|
|
6
|
+
type $$ComponentProps = {
|
|
7
|
+
gg?: GgCallSiteInfo;
|
|
8
|
+
url?: string;
|
|
9
|
+
fileName?: string;
|
|
4
10
|
title?: string;
|
|
5
11
|
};
|
|
6
12
|
declare const OpenInEditorLink: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-specific debug implementation.
|
|
3
|
+
*
|
|
4
|
+
* Output: console.debug with %c CSS color formatting.
|
|
5
|
+
* Persistence: localStorage.debug
|
|
6
|
+
* Format (patched): +123ms namespace message
|
|
7
|
+
*/
|
|
8
|
+
import { type DebugFactory } from './common.js';
|
|
9
|
+
declare const debug: DebugFactory;
|
|
10
|
+
export default debug;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-specific debug implementation.
|
|
3
|
+
*
|
|
4
|
+
* Output: console.debug with %c CSS color formatting.
|
|
5
|
+
* Persistence: localStorage.debug
|
|
6
|
+
* Format (patched): +123ms namespace message
|
|
7
|
+
*/
|
|
8
|
+
import { setup, humanize } from './common.js';
|
|
9
|
+
/**
|
|
10
|
+
* 76 hex colors — identical to debug@4 browser.js for color-hash stability.
|
|
11
|
+
*/
|
|
12
|
+
const colors = [
|
|
13
|
+
'#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF',
|
|
14
|
+
'#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99',
|
|
15
|
+
'#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF',
|
|
16
|
+
'#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33',
|
|
17
|
+
'#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF',
|
|
18
|
+
'#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF',
|
|
19
|
+
'#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033',
|
|
20
|
+
'#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333',
|
|
21
|
+
'#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633',
|
|
22
|
+
'#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033',
|
|
23
|
+
'#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333',
|
|
24
|
+
'#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633',
|
|
25
|
+
'#FF9900', '#FF9933', '#FFCC00', '#FFCC33'
|
|
26
|
+
];
|
|
27
|
+
function useColors() {
|
|
28
|
+
// Modern browsers all support %c — simplified from debug's original checks
|
|
29
|
+
return typeof document !== 'undefined' || typeof navigator !== 'undefined';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Format args with color CSS and gg's patched prefix order:
|
|
33
|
+
* +123ms namespace message
|
|
34
|
+
*/
|
|
35
|
+
function formatArgs(args) {
|
|
36
|
+
const h = humanize(this.diff);
|
|
37
|
+
const prefix = ('+' + h).padStart(6);
|
|
38
|
+
args[0] = (this.useColors ? '%c' : '') +
|
|
39
|
+
`${prefix} ${this.namespace}` +
|
|
40
|
+
(this.useColors ? ' %c' : ' ') +
|
|
41
|
+
args[0] +
|
|
42
|
+
(this.useColors ? '%c ' : ' ');
|
|
43
|
+
if (!this.useColors)
|
|
44
|
+
return;
|
|
45
|
+
const c = 'color: ' + this.color;
|
|
46
|
+
args.splice(1, 0, c, 'color: inherit');
|
|
47
|
+
// Insert CSS for the final %c
|
|
48
|
+
let index = 0;
|
|
49
|
+
let lastC = 0;
|
|
50
|
+
args[0].replace(/%[a-zA-Z%]/g, (match) => {
|
|
51
|
+
if (match === '%%')
|
|
52
|
+
return match;
|
|
53
|
+
index++;
|
|
54
|
+
if (match === '%c')
|
|
55
|
+
lastC = index;
|
|
56
|
+
return match;
|
|
57
|
+
});
|
|
58
|
+
args.splice(lastC, 0, c);
|
|
59
|
+
}
|
|
60
|
+
function save(namespaces) {
|
|
61
|
+
try {
|
|
62
|
+
if (namespaces) {
|
|
63
|
+
localStorage.setItem('debug', namespaces);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
localStorage.removeItem('debug');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// localStorage may not be available
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function load() {
|
|
74
|
+
try {
|
|
75
|
+
return localStorage.getItem('debug') || localStorage.getItem('DEBUG') || '';
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return '';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const log = console.debug || console.log || (() => { });
|
|
82
|
+
const env = {
|
|
83
|
+
formatArgs,
|
|
84
|
+
save,
|
|
85
|
+
load,
|
|
86
|
+
useColors,
|
|
87
|
+
colors,
|
|
88
|
+
log,
|
|
89
|
+
formatters: {
|
|
90
|
+
/** %j → JSON.stringify (preserved for compatibility) */
|
|
91
|
+
j(v) {
|
|
92
|
+
try {
|
|
93
|
+
return JSON.stringify(v);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
return '[UnexpectedJSONParseError]: ' + e.message;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const debug = setup(env);
|
|
102
|
+
export default debug;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal debug implementation — replaces the `debug` npm package.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: createDebug factory, enable/disable, namespace matching,
|
|
5
|
+
* color selection, and humanize (ms formatting).
|
|
6
|
+
*/
|
|
7
|
+
/** Format ms like debug's `ms` package: 0ms, 500ms, 5s, 2m, 1h, 3d */
|
|
8
|
+
export declare function humanize(ms: number): string;
|
|
9
|
+
export interface Debugger {
|
|
10
|
+
(...args: unknown[]): void;
|
|
11
|
+
namespace: string;
|
|
12
|
+
color: string;
|
|
13
|
+
diff: number;
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
useColors: boolean;
|
|
16
|
+
formatArgs: (args: unknown[]) => void;
|
|
17
|
+
log: ((...args: unknown[]) => void) | null;
|
|
18
|
+
}
|
|
19
|
+
export interface DebugFactory {
|
|
20
|
+
(namespace: string): Debugger;
|
|
21
|
+
enable: (namespaces: string) => void;
|
|
22
|
+
disable: () => string;
|
|
23
|
+
enabled: (namespace: string) => boolean;
|
|
24
|
+
humanize: typeof humanize;
|
|
25
|
+
names: string[];
|
|
26
|
+
skips: string[];
|
|
27
|
+
namespaces: string;
|
|
28
|
+
formatters: Record<string, (this: Debugger, val: unknown) => string>;
|
|
29
|
+
}
|
|
30
|
+
/** Platform-specific hooks provided by browser.ts or node.ts */
|
|
31
|
+
export interface DebugEnv {
|
|
32
|
+
formatArgs: (this: Debugger, args: unknown[]) => void;
|
|
33
|
+
save: (namespaces: string) => void;
|
|
34
|
+
load: () => string;
|
|
35
|
+
useColors: () => boolean;
|
|
36
|
+
colors: string[] | number[];
|
|
37
|
+
log: (...args: unknown[]) => void;
|
|
38
|
+
formatters?: Record<string, (this: Debugger, val: unknown) => string>;
|
|
39
|
+
init?: (instance: Debugger) => void;
|
|
40
|
+
}
|
|
41
|
+
export declare function setup(env: DebugEnv): DebugFactory;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal debug implementation — replaces the `debug` npm package.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: createDebug factory, enable/disable, namespace matching,
|
|
5
|
+
* color selection, and humanize (ms formatting).
|
|
6
|
+
*/
|
|
7
|
+
/** Format ms like debug's `ms` package: 0ms, 500ms, 5s, 2m, 1h, 3d */
|
|
8
|
+
export function humanize(ms) {
|
|
9
|
+
const abs = Math.abs(ms);
|
|
10
|
+
if (abs >= 86_400_000)
|
|
11
|
+
return Math.round(ms / 86_400_000) + 'd';
|
|
12
|
+
if (abs >= 3_600_000)
|
|
13
|
+
return Math.round(ms / 3_600_000) + 'h';
|
|
14
|
+
if (abs >= 60_000)
|
|
15
|
+
return Math.round(ms / 60_000) + 'm';
|
|
16
|
+
if (abs >= 1_000)
|
|
17
|
+
return Math.round(ms / 1_000) + 's';
|
|
18
|
+
return ms + 'ms';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Wildcard pattern matching (same algorithm as debug's `matchesTemplate`).
|
|
22
|
+
* Supports `*` as a wildcard that matches any sequence of characters.
|
|
23
|
+
*/
|
|
24
|
+
function matchesTemplate(search, template) {
|
|
25
|
+
let si = 0;
|
|
26
|
+
let ti = 0;
|
|
27
|
+
let starIdx = -1;
|
|
28
|
+
let matchIdx = 0;
|
|
29
|
+
while (si < search.length) {
|
|
30
|
+
if (ti < template.length && (template[ti] === search[si] || template[ti] === '*')) {
|
|
31
|
+
if (template[ti] === '*') {
|
|
32
|
+
starIdx = ti;
|
|
33
|
+
matchIdx = si;
|
|
34
|
+
ti++;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
si++;
|
|
38
|
+
ti++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else if (starIdx !== -1) {
|
|
42
|
+
ti = starIdx + 1;
|
|
43
|
+
matchIdx++;
|
|
44
|
+
si = matchIdx;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
while (ti < template.length && template[ti] === '*') {
|
|
51
|
+
ti++;
|
|
52
|
+
}
|
|
53
|
+
return ti === template.length;
|
|
54
|
+
}
|
|
55
|
+
// ── Factory ────────────────────────────────────────────────────────────
|
|
56
|
+
export function setup(env) {
|
|
57
|
+
/** Deterministic color for a namespace (same hash as debug@4) */
|
|
58
|
+
function selectColor(namespace) {
|
|
59
|
+
let hash = 0;
|
|
60
|
+
for (let i = 0; i < namespace.length; i++) {
|
|
61
|
+
hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
|
|
62
|
+
hash |= 0;
|
|
63
|
+
}
|
|
64
|
+
return env.colors[Math.abs(hash) % env.colors.length];
|
|
65
|
+
}
|
|
66
|
+
// Active include/exclude lists
|
|
67
|
+
let names = [];
|
|
68
|
+
let skips = [];
|
|
69
|
+
let currentNamespaces = '';
|
|
70
|
+
function enable(namespaces) {
|
|
71
|
+
env.save(namespaces);
|
|
72
|
+
currentNamespaces = namespaces;
|
|
73
|
+
names = [];
|
|
74
|
+
skips = [];
|
|
75
|
+
const parts = (typeof namespaces === 'string' ? namespaces : '')
|
|
76
|
+
.trim()
|
|
77
|
+
.replace(/\s+/g, ',')
|
|
78
|
+
.split(',')
|
|
79
|
+
.filter(Boolean);
|
|
80
|
+
for (const part of parts) {
|
|
81
|
+
if (part[0] === '-') {
|
|
82
|
+
skips.push(part.slice(1));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
names.push(part);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Update factory-level arrays for external inspection
|
|
89
|
+
factory.names = names;
|
|
90
|
+
factory.skips = skips;
|
|
91
|
+
factory.namespaces = currentNamespaces;
|
|
92
|
+
}
|
|
93
|
+
function disable() {
|
|
94
|
+
const prev = [
|
|
95
|
+
...names,
|
|
96
|
+
...skips.map((ns) => '-' + ns)
|
|
97
|
+
].join(',');
|
|
98
|
+
enable('');
|
|
99
|
+
return prev;
|
|
100
|
+
}
|
|
101
|
+
function enabled(name) {
|
|
102
|
+
for (const skip of skips) {
|
|
103
|
+
if (matchesTemplate(name, skip))
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
for (const ns of names) {
|
|
107
|
+
if (matchesTemplate(name, ns))
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
// ── createDebug ────────────────────────────────────────────────────
|
|
113
|
+
function createDebug(namespace) {
|
|
114
|
+
let prevTime;
|
|
115
|
+
let enableOverride = null;
|
|
116
|
+
let namespacesCache;
|
|
117
|
+
let enabledCache;
|
|
118
|
+
const debug = function (...args) {
|
|
119
|
+
if (!debug.enabled)
|
|
120
|
+
return;
|
|
121
|
+
const curr = Date.now();
|
|
122
|
+
const ms = curr - (prevTime || curr);
|
|
123
|
+
debug.diff = ms;
|
|
124
|
+
prevTime = curr;
|
|
125
|
+
// Coerce first arg
|
|
126
|
+
if (typeof args[0] !== 'string') {
|
|
127
|
+
args.unshift('%O');
|
|
128
|
+
}
|
|
129
|
+
// Apply %format replacements
|
|
130
|
+
let idx = 0;
|
|
131
|
+
args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, fmt) => {
|
|
132
|
+
if (match === '%%')
|
|
133
|
+
return '%';
|
|
134
|
+
idx++;
|
|
135
|
+
const formatter = factory.formatters[fmt];
|
|
136
|
+
if (typeof formatter === 'function') {
|
|
137
|
+
const val = args[idx];
|
|
138
|
+
match = formatter.call(debug, val);
|
|
139
|
+
args.splice(idx, 1);
|
|
140
|
+
idx--;
|
|
141
|
+
}
|
|
142
|
+
return match;
|
|
143
|
+
});
|
|
144
|
+
// Platform-specific formatting (colors, prefix)
|
|
145
|
+
debug.formatArgs(args);
|
|
146
|
+
const logFn = debug.log || env.log;
|
|
147
|
+
logFn.apply(debug, args);
|
|
148
|
+
};
|
|
149
|
+
debug.namespace = namespace;
|
|
150
|
+
debug.useColors = env.useColors();
|
|
151
|
+
debug.color = String(selectColor(namespace));
|
|
152
|
+
debug.diff = 0;
|
|
153
|
+
debug.log = null;
|
|
154
|
+
debug.formatArgs = function (args) {
|
|
155
|
+
env.formatArgs.call(debug, args);
|
|
156
|
+
};
|
|
157
|
+
Object.defineProperty(debug, 'enabled', {
|
|
158
|
+
enumerable: true,
|
|
159
|
+
configurable: false,
|
|
160
|
+
get: () => {
|
|
161
|
+
if (enableOverride !== null)
|
|
162
|
+
return enableOverride;
|
|
163
|
+
if (namespacesCache !== currentNamespaces) {
|
|
164
|
+
namespacesCache = currentNamespaces;
|
|
165
|
+
enabledCache = enabled(namespace);
|
|
166
|
+
}
|
|
167
|
+
return enabledCache;
|
|
168
|
+
},
|
|
169
|
+
set: (v) => {
|
|
170
|
+
enableOverride = v;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
if (env.init) {
|
|
174
|
+
env.init(debug);
|
|
175
|
+
}
|
|
176
|
+
return debug;
|
|
177
|
+
}
|
|
178
|
+
// ── Assemble factory ───────────────────────────────────────────────
|
|
179
|
+
const factory = createDebug;
|
|
180
|
+
factory.enable = enable;
|
|
181
|
+
factory.disable = disable;
|
|
182
|
+
factory.enabled = enabled;
|
|
183
|
+
factory.humanize = humanize;
|
|
184
|
+
factory.names = names;
|
|
185
|
+
factory.skips = skips;
|
|
186
|
+
factory.namespaces = '';
|
|
187
|
+
factory.formatters = { ...env.formatters };
|
|
188
|
+
// Initialize from persisted namespaces
|
|
189
|
+
enable(env.load());
|
|
190
|
+
return factory;
|
|
191
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug entry point — selects browser or node implementation.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the DebugFactory and Debugger types for consumers.
|
|
5
|
+
*/
|
|
6
|
+
import type { DebugFactory } from './common.js';
|
|
7
|
+
export type { DebugFactory, Debugger } from './common.js';
|
|
8
|
+
declare const _default: DebugFactory;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug entry point — selects browser or node implementation.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the DebugFactory and Debugger types for consumers.
|
|
5
|
+
*/
|
|
6
|
+
import { BROWSER } from 'esm-env';
|
|
7
|
+
// Conditional import: browser.ts for browsers, node.ts for Node/Deno/Bun
|
|
8
|
+
const { default: debug } = BROWSER
|
|
9
|
+
? await import('./browser.js')
|
|
10
|
+
: await import('./node.js');
|
|
11
|
+
export default debug;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js-specific debug implementation.
|
|
3
|
+
*
|
|
4
|
+
* Output: process.stderr via util.formatWithOptions.
|
|
5
|
+
* Persistence: process.env.DEBUG
|
|
6
|
+
* Format (patched): +123ms namespace message (ANSI colored)
|
|
7
|
+
*/
|
|
8
|
+
import { type DebugFactory } from './common.js';
|
|
9
|
+
declare const debug: DebugFactory;
|
|
10
|
+
export default debug;
|