@leftium/gg 0.0.28 → 0.0.30
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/dist/eruda/plugin.js
CHANGED
|
@@ -95,6 +95,20 @@ export function createGgPlugin(options, gg) {
|
|
|
95
95
|
}
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
|
+
function soloNamespace(namespace) {
|
|
99
|
+
const ns = namespace.trim();
|
|
100
|
+
// Toggle: if already soloed on this namespace, restore all
|
|
101
|
+
if (filterPattern === ns) {
|
|
102
|
+
filterPattern = 'gg:*';
|
|
103
|
+
enabledNamespaces.clear();
|
|
104
|
+
getAllCapturedNamespaces().forEach((n) => enabledNamespaces.add(n));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Solo: show only this namespace
|
|
108
|
+
filterPattern = ns;
|
|
109
|
+
enabledNamespaces.clear();
|
|
110
|
+
enabledNamespaces.add(ns);
|
|
111
|
+
}
|
|
98
112
|
function simplifyPattern(pattern) {
|
|
99
113
|
if (!pattern)
|
|
100
114
|
return '';
|
|
@@ -172,7 +186,11 @@ export function createGgPlugin(options, gg) {
|
|
|
172
186
|
}
|
|
173
187
|
function gridColumns() {
|
|
174
188
|
const ns = nsColWidth !== null ? `${nsColWidth}px` : 'auto';
|
|
175
|
-
// diff | ns | handle | content
|
|
189
|
+
// When filter expanded: icons | diff | ns | handle | content
|
|
190
|
+
// When collapsed: diff | ns | handle | content
|
|
191
|
+
if (filterExpanded) {
|
|
192
|
+
return `auto auto ${ns} 4px 1fr`;
|
|
193
|
+
}
|
|
176
194
|
return `auto ${ns} 4px 1fr`;
|
|
177
195
|
}
|
|
178
196
|
function buildHTML() {
|
|
@@ -191,6 +209,7 @@ export function createGgPlugin(options, gg) {
|
|
|
191
209
|
.gg-log-header {
|
|
192
210
|
display: contents;
|
|
193
211
|
}
|
|
212
|
+
.gg-log-icons,
|
|
194
213
|
.gg-log-diff,
|
|
195
214
|
.gg-log-ns,
|
|
196
215
|
.gg-log-handle,
|
|
@@ -199,6 +218,32 @@ export function createGgPlugin(options, gg) {
|
|
|
199
218
|
align-self: start !important;
|
|
200
219
|
border-top: 1px solid rgba(0,0,0,0.05);
|
|
201
220
|
}
|
|
221
|
+
.gg-log-icons {
|
|
222
|
+
display: flex;
|
|
223
|
+
gap: 2px;
|
|
224
|
+
padding: 0 4px 0 0;
|
|
225
|
+
white-space: nowrap;
|
|
226
|
+
align-self: stretch !important;
|
|
227
|
+
}
|
|
228
|
+
.gg-log-icons button {
|
|
229
|
+
all: unset;
|
|
230
|
+
cursor: pointer;
|
|
231
|
+
opacity: 0.35;
|
|
232
|
+
padding: 4px 10px;
|
|
233
|
+
line-height: 1;
|
|
234
|
+
display: flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
}
|
|
237
|
+
.gg-log-icons button:hover {
|
|
238
|
+
opacity: 1;
|
|
239
|
+
background: rgba(0,0,0,0.05);
|
|
240
|
+
}
|
|
241
|
+
.gg-solo-target {
|
|
242
|
+
cursor: pointer;
|
|
243
|
+
}
|
|
244
|
+
.gg-solo-target:hover {
|
|
245
|
+
background: rgba(0,0,0,0.05);
|
|
246
|
+
}
|
|
202
247
|
.gg-details {
|
|
203
248
|
grid-column: 1 / -1;
|
|
204
249
|
border-top: none;
|
|
@@ -242,15 +287,6 @@ export function createGgPlugin(options, gg) {
|
|
|
242
287
|
word-break: break-word;
|
|
243
288
|
padding: 4px 0;
|
|
244
289
|
}
|
|
245
|
-
/* Make header clickable for filtering when filters are expanded */
|
|
246
|
-
.gg-log-header.clickable {
|
|
247
|
-
cursor: pointer;
|
|
248
|
-
}
|
|
249
|
-
/* Desktop: highlight child elements since header has display: contents */
|
|
250
|
-
.gg-log-header.clickable:hover .gg-log-diff,
|
|
251
|
-
.gg-log-header.clickable:hover .gg-log-ns {
|
|
252
|
-
background: rgba(0,0,0,0.05);
|
|
253
|
-
}
|
|
254
290
|
.gg-filter-panel {
|
|
255
291
|
background: #f5f5f5;
|
|
256
292
|
padding: 10px;
|
|
@@ -333,6 +369,7 @@ export function createGgPlugin(options, gg) {
|
|
|
333
369
|
.gg-log-entry:not(:first-child) {
|
|
334
370
|
border-top: 1px solid rgba(0,0,0,0.05);
|
|
335
371
|
}
|
|
372
|
+
.gg-log-icons,
|
|
336
373
|
.gg-log-diff,
|
|
337
374
|
.gg-log-ns,
|
|
338
375
|
.gg-log-handle,
|
|
@@ -347,18 +384,6 @@ export function createGgPlugin(options, gg) {
|
|
|
347
384
|
margin-bottom: 4px;
|
|
348
385
|
min-width: 0;
|
|
349
386
|
}
|
|
350
|
-
/* Mobile: hover on container since it's not display: contents */
|
|
351
|
-
.gg-log-header.clickable {
|
|
352
|
-
padding: 2px 0;
|
|
353
|
-
}
|
|
354
|
-
.gg-log-header.clickable:hover {
|
|
355
|
-
background: rgba(0,0,0,0.05);
|
|
356
|
-
}
|
|
357
|
-
/* Override desktop child hover on mobile */
|
|
358
|
-
.gg-log-header.clickable:hover .gg-log-diff,
|
|
359
|
-
.gg-log-header.clickable:hover .gg-log-ns {
|
|
360
|
-
background: transparent;
|
|
361
|
-
}
|
|
362
387
|
.gg-log-diff {
|
|
363
388
|
padding: 0;
|
|
364
389
|
text-align: left;
|
|
@@ -612,17 +637,42 @@ export function createGgPlugin(options, gg) {
|
|
|
612
637
|
}
|
|
613
638
|
return;
|
|
614
639
|
}
|
|
615
|
-
// Handle
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
target
|
|
619
|
-
const
|
|
620
|
-
|
|
640
|
+
// Handle filter icon clicks (hide / solo)
|
|
641
|
+
if (target?.classList?.contains('gg-icon-hide') ||
|
|
642
|
+
target?.classList?.contains('gg-icon-solo')) {
|
|
643
|
+
const iconsDiv = target.closest('.gg-log-icons');
|
|
644
|
+
const namespace = iconsDiv?.getAttribute('data-namespace');
|
|
645
|
+
if (!namespace)
|
|
646
|
+
return;
|
|
647
|
+
if (target.classList.contains('gg-icon-hide')) {
|
|
648
|
+
toggleNamespace(namespace, false);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
soloNamespace(namespace);
|
|
652
|
+
}
|
|
653
|
+
localStorage.setItem('debug', filterPattern);
|
|
654
|
+
renderFilterUI();
|
|
655
|
+
renderLogs();
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
// Handle clicking diff/ns cells to solo (same as 🎯)
|
|
659
|
+
if (target?.classList?.contains('gg-solo-target')) {
|
|
660
|
+
const namespace = target.getAttribute('data-namespace');
|
|
621
661
|
if (!namespace)
|
|
622
662
|
return;
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
663
|
+
soloNamespace(namespace);
|
|
664
|
+
localStorage.setItem('debug', filterPattern);
|
|
665
|
+
renderFilterUI();
|
|
666
|
+
renderLogs();
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
// Clicking background (container or grid, not a log element) restores all
|
|
670
|
+
if (filterExpanded &&
|
|
671
|
+
filterPattern !== 'gg:*' &&
|
|
672
|
+
(target === containerEl || target?.classList?.contains('gg-log-grid'))) {
|
|
673
|
+
filterPattern = 'gg:*';
|
|
674
|
+
enabledNamespaces.clear();
|
|
675
|
+
getAllCapturedNamespaces().forEach((ns) => enabledNamespaces.add(ns));
|
|
626
676
|
localStorage.setItem('debug', filterPattern);
|
|
627
677
|
renderFilterUI();
|
|
628
678
|
renderLogs();
|
|
@@ -727,20 +777,22 @@ export function createGgPlugin(options, gg) {
|
|
|
727
777
|
})
|
|
728
778
|
.join(' ');
|
|
729
779
|
}
|
|
730
|
-
//
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
const filterIcon = filterExpanded
|
|
737
|
-
? '<span style="font-weight: bold; color: #000; opacity: 0.6;">× </span>'
|
|
780
|
+
// Filter icons column (only when expanded)
|
|
781
|
+
const iconsCol = filterExpanded
|
|
782
|
+
? `<div class="gg-log-icons" data-namespace="${ns}">` +
|
|
783
|
+
`<button class="gg-icon-hide" title="Hide this namespace">🗑</button>` +
|
|
784
|
+
`<button class="gg-icon-solo" title="Show only this namespace">🎯</button>` +
|
|
785
|
+
`</div>`
|
|
738
786
|
: '';
|
|
787
|
+
// When filter expanded, diff+ns are clickable (solo) with data-namespace
|
|
788
|
+
const soloAttr = filterExpanded ? ` data-namespace="${ns}"` : '';
|
|
789
|
+
const soloClass = filterExpanded ? ' gg-solo-target' : '';
|
|
739
790
|
// Desktop: grid layout, Mobile: stacked layout
|
|
740
791
|
return (`<div class="gg-log-entry">` +
|
|
741
|
-
`<div class="
|
|
742
|
-
|
|
743
|
-
`<div class="gg-log-
|
|
792
|
+
`<div class="gg-log-header">` +
|
|
793
|
+
iconsCol +
|
|
794
|
+
`<div class="gg-log-diff${soloClass}" style="color: ${color};"${soloAttr}>${diff}</div>` +
|
|
795
|
+
`<div class="gg-log-ns${soloClass}" style="color: ${color};"${soloAttr}>${ns}</div>` +
|
|
744
796
|
`<div class="gg-log-handle"></div>` +
|
|
745
797
|
`</div>` +
|
|
746
798
|
`<div class="gg-log-content">${argsHTML}</div>` +
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
-
export interface
|
|
2
|
+
export interface GgCallSitesPluginOptions {
|
|
3
3
|
/**
|
|
4
4
|
* Pattern to strip from file paths to produce short callpoints.
|
|
5
5
|
* Should match up to and including the source root folder.
|
|
@@ -22,10 +22,10 @@ export interface GgTagPluginOptions {
|
|
|
22
22
|
*
|
|
23
23
|
* @example
|
|
24
24
|
* // vite.config.ts
|
|
25
|
-
* import {
|
|
25
|
+
* import { ggCallSitesPlugin } from '@leftium/gg';
|
|
26
26
|
*
|
|
27
27
|
* export default defineConfig({
|
|
28
|
-
* plugins: [
|
|
28
|
+
* plugins: [ggCallSitesPlugin()]
|
|
29
29
|
* });
|
|
30
30
|
*/
|
|
31
|
-
export default function
|
|
31
|
+
export default function ggCallSitesPlugin(options?: GgCallSitesPluginOptions): Plugin;
|
|
@@ -9,17 +9,27 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* // vite.config.ts
|
|
12
|
-
* import {
|
|
12
|
+
* import { ggCallSitesPlugin } from '@leftium/gg';
|
|
13
13
|
*
|
|
14
14
|
* export default defineConfig({
|
|
15
|
-
* plugins: [
|
|
15
|
+
* plugins: [ggCallSitesPlugin()]
|
|
16
16
|
* });
|
|
17
17
|
*/
|
|
18
|
-
export default function
|
|
18
|
+
export default function ggCallSitesPlugin(options = {}) {
|
|
19
19
|
const srcRootPattern = options.srcRootPattern ?? '.*?(/(?:src|chunks)/)';
|
|
20
20
|
const srcRootRegex = new RegExp(srcRootPattern, 'i');
|
|
21
21
|
return {
|
|
22
|
-
name: 'gg-
|
|
22
|
+
name: 'gg-call-sites',
|
|
23
|
+
config() {
|
|
24
|
+
// Set a compile-time flag so gg() can detect the plugin is installed.
|
|
25
|
+
// Vite replaces all occurrences of __GG_TAG_PLUGIN__ with true at build time,
|
|
26
|
+
// before any code executes — no ordering issues.
|
|
27
|
+
return {
|
|
28
|
+
define: {
|
|
29
|
+
__GG_TAG_PLUGIN__: 'true'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
},
|
|
23
33
|
transform(code, id) {
|
|
24
34
|
// Only process JS/TS/Svelte files
|
|
25
35
|
if (!/\.(js|ts|svelte|jsx|tsx|mjs|mts)(\?.*)?$/.test(id))
|
package/dist/gg.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import debugFactory from './debug.js';
|
|
2
2
|
import ErrorStackParser from 'error-stack-parser';
|
|
3
3
|
import { BROWSER, DEV } from 'esm-env';
|
|
4
|
+
const _ggCallSitesPlugin = typeof __GG_TAG_PLUGIN__ !== 'undefined' ? __GG_TAG_PLUGIN__ : false;
|
|
4
5
|
/**
|
|
5
6
|
* Creates a debug instance with custom formatArgs to add namespace padding
|
|
6
7
|
* Padding is done at format time, not in the namespace itself, to keep colors stable
|
|
@@ -185,9 +186,12 @@ export function gg(...args) {
|
|
|
185
186
|
let url = '';
|
|
186
187
|
let stack = [];
|
|
187
188
|
let namespace = 'gg:';
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
if
|
|
189
|
+
// When ggCallSitesPlugin is installed, all bare gg() calls are rewritten to gg.ns()
|
|
190
|
+
// at build time, so this code path only runs for un-transformed calls.
|
|
191
|
+
// Skip expensive stack parsing if the plugin is handling callpoints.
|
|
192
|
+
// In development without plugin: calculate detailed callpoint information
|
|
193
|
+
// In production without plugin: skip expensive stack parsing and use simple namespace
|
|
194
|
+
if (DEV && !_ggCallSitesPlugin) {
|
|
191
195
|
// Ignore first stack frame, which is always the call to gg() itself.
|
|
192
196
|
stack = ErrorStackParser.parse(new Error()).splice(1);
|
|
193
197
|
// Example: http://localhost:5173/src/routes/+page.svelte
|
|
@@ -258,7 +262,7 @@ export function gg(...args) {
|
|
|
258
262
|
/**
|
|
259
263
|
* gg.ns() - Log with an explicit namespace (callpoint label).
|
|
260
264
|
*
|
|
261
|
-
* In production builds, the
|
|
265
|
+
* In production builds, the ggCallSitesPlugin Vite plugin rewrites bare gg() calls
|
|
262
266
|
* to gg.ns('callpoint', ...) so each call site gets a unique namespace even
|
|
263
267
|
* after minification. Users can also call gg.ns() directly to set a meaningful
|
|
264
268
|
* label that survives across builds.
|
|
@@ -514,10 +518,6 @@ export async function runGgDiagnostics() {
|
|
|
514
518
|
if (BROWSER) {
|
|
515
519
|
const hint = makeHint(!ggLogTest.enabled, " (Try `localStorage.debug = 'gg:*'`)");
|
|
516
520
|
message(`${checkbox(ggLogTest.enabled)} localStorage.debug: ${localStorage?.debug}${hint}`);
|
|
517
|
-
if (DEV) {
|
|
518
|
-
const { status } = await fetch('/__open-in-editor?file=+');
|
|
519
|
-
message(makeHint(status === 222, `✅ (optional) open-in-editor vite plugin detected! (status code: ${status})`, `⚠️ (optional) open-in-editor vite plugin not detected. (status code: ${status}.) Add plugin in vite.config.ts`));
|
|
520
|
-
}
|
|
521
521
|
}
|
|
522
522
|
else {
|
|
523
523
|
const hint = makeHint(!ggLogTest.enabled, ' (Try `DEBUG=gg:* npm dev`)');
|
|
@@ -526,6 +526,12 @@ export async function runGgDiagnostics() {
|
|
|
526
526
|
}
|
|
527
527
|
message(`${checkbox(ggLogTest.enabled)} DEBUG env variable: ${process?.env?.DEBUG}${hint}`);
|
|
528
528
|
}
|
|
529
|
+
// Optional plugin diagnostics listed last
|
|
530
|
+
message(makeHint(_ggCallSitesPlugin, `✅ (optional) gg-call-sites vite plugin detected! Call-site namespaces baked in at build time.`, `⚠️ (optional) gg-call-sites vite plugin not detected. Add ggCallSitesPlugin() to vite.config.ts for build-time call-site namespaces (needed for useful namespaces in prod, faster/more reliable in dev)`));
|
|
531
|
+
if (BROWSER && DEV) {
|
|
532
|
+
const { status } = await fetch('/__open-in-editor?file=+');
|
|
533
|
+
message(makeHint(status === 222, `✅ (optional) open-in-editor vite plugin detected! (status code: ${status}) Clickable links open source files in editor.`, `⚠️ (optional) open-in-editor vite plugin not detected. (status code: ${status}) Add openInEditorPlugin() to vite.config.ts for clickable links that open source files in editor`));
|
|
534
|
+
}
|
|
529
535
|
// Use plain console.log for diagnostics - appears in Eruda's Console tab
|
|
530
536
|
console.log(ggMessage);
|
|
531
537
|
// Reset namespace width after configuration check
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { gg, fg, bg } from './gg.js';
|
|
2
2
|
import openInEditorPlugin from './open-in-editor.js';
|
|
3
|
-
import
|
|
4
|
-
export { gg, fg, bg, openInEditorPlugin,
|
|
3
|
+
import ggCallSitesPlugin from './gg-call-sites-plugin.js';
|
|
4
|
+
export { gg, fg, bg, openInEditorPlugin, ggCallSitesPlugin };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Reexport your entry components here
|
|
2
2
|
import { gg, fg, bg } from './gg.js';
|
|
3
3
|
import openInEditorPlugin from './open-in-editor.js';
|
|
4
|
-
import
|
|
5
|
-
export { gg, fg, bg, openInEditorPlugin,
|
|
4
|
+
import ggCallSitesPlugin from './gg-call-sites-plugin.js';
|
|
5
|
+
export { gg, fg, bg, openInEditorPlugin, ggCallSitesPlugin };
|