vite-plugin-source-locator 1.1.1 → 1.1.2
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 +33 -10
- package/dist/client/controller.js +8 -8
- package/dist/client/overlay.d.ts +2 -2
- package/dist/client/overlay.js +4 -4
- package/dist/client/preference.d.ts +1 -4
- package/dist/client/preference.js +3 -17
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js +10 -3
- package/dist/vite/editors.d.ts +2 -2
- package/dist/vite/editors.js +7 -3
- package/dist/vite/index.js +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,11 +42,11 @@ No `main.tsx` wiring required. The plugin auto-injects the client overlay in dev
|
|
|
42
42
|
|
|
43
43
|
## Pick Mode
|
|
44
44
|
|
|
45
|
-
1. Click the badge (bottom-right): **Source Locator (
|
|
45
|
+
1. Click the badge (bottom-right): **Source Locator (auto) — click to pick**
|
|
46
46
|
2. Hover elements — blue highlight + file paths in tooltip
|
|
47
47
|
3. Click to open source — cycles **TSX → CSS → TSX** when both exist
|
|
48
48
|
4. **Esc** — cancel pick mode
|
|
49
|
-
5. **Shift+L** — cycle IDE
|
|
49
|
+
5. **Shift+L** — cycle IDE (session only, resets on refresh)
|
|
50
50
|
|
|
51
51
|
## Exports
|
|
52
52
|
|
|
@@ -63,7 +63,7 @@ sourceLocator({
|
|
|
63
63
|
enabled: true,
|
|
64
64
|
endpoint: '/__open-in-editor',
|
|
65
65
|
attribute: 'data-source',
|
|
66
|
-
ides: ['cursor', 'vscode', 'webstorm'],
|
|
66
|
+
ides: ['auto', 'cursor', 'vscode', 'webstorm'],
|
|
67
67
|
theme: 'light',
|
|
68
68
|
})
|
|
69
69
|
```
|
|
@@ -89,7 +89,7 @@ import { initSourceLocator } from 'vite-plugin-source-locator/client'
|
|
|
89
89
|
initSourceLocator({
|
|
90
90
|
endpoint: '/__open-in-editor',
|
|
91
91
|
attribute: 'data-source',
|
|
92
|
-
ides: ['cursor', 'vscode', 'webstorm'],
|
|
92
|
+
ides: ['auto', 'cursor', 'vscode', 'webstorm'],
|
|
93
93
|
theme: {
|
|
94
94
|
background: '#ffffff',
|
|
95
95
|
text: '#000000',
|
|
@@ -132,7 +132,7 @@ import { initSourceLocator } from 'vite-plugin-source-locator/client'
|
|
|
132
132
|
initSourceLocator({
|
|
133
133
|
endpoint: '/__open-in-editor',
|
|
134
134
|
attribute: 'data-source',
|
|
135
|
-
ides: ['cursor', 'vscode', 'webstorm'],
|
|
135
|
+
ides: ['auto', 'cursor', 'vscode', 'webstorm'],
|
|
136
136
|
theme: 'blue',
|
|
137
137
|
})
|
|
138
138
|
```
|
|
@@ -141,7 +141,32 @@ initSourceLocator({
|
|
|
141
141
|
|
|
142
142
|
IDE opening works on **macOS, Windows, and Linux** via [`launch-editor`](https://github.com/vitejs/launch-editor).
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
### Auto detection (default)
|
|
145
|
+
|
|
146
|
+
By default, `ides` includes `'auto'` as the first entry. In `auto` mode, the plugin detects your open IDE:
|
|
147
|
+
|
|
148
|
+
1. `LAUNCH_EDITOR` / `REACT_EDITOR` environment variable
|
|
149
|
+
2. Running editor process (VS Code, Cursor, WebStorm, etc.)
|
|
150
|
+
3. `VISUAL` / `EDITOR` environment variable
|
|
151
|
+
|
|
152
|
+
No CLI on `PATH` is required if the editor is already running.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// auto-detect open IDE (default)
|
|
156
|
+
sourceLocator()
|
|
157
|
+
|
|
158
|
+
// VS Code only
|
|
159
|
+
sourceLocator({ ides: ['vscode'] })
|
|
160
|
+
|
|
161
|
+
// auto + manual override with Shift+L (session only)
|
|
162
|
+
sourceLocator({ ides: ['auto', 'vscode'] })
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The first entry in `ides` is the default. Shift+L cycles through the list in memory (resets on page refresh).
|
|
166
|
+
|
|
167
|
+
### Explicit editor
|
|
168
|
+
|
|
169
|
+
When not using `auto`, the editor CLI should be on your `PATH`:
|
|
145
170
|
|
|
146
171
|
| IDE | CLI command |
|
|
147
172
|
|-----|-------------|
|
|
@@ -149,13 +174,11 @@ The editor CLI must be available on your `PATH`:
|
|
|
149
174
|
| VS Code | `code` |
|
|
150
175
|
| WebStorm | `webstorm` |
|
|
151
176
|
|
|
152
|
-
|
|
177
|
+
Override with environment variables:
|
|
153
178
|
|
|
154
|
-
- `LAUNCH_EDITOR=
|
|
179
|
+
- `LAUNCH_EDITOR=code`
|
|
155
180
|
- `REACT_EDITOR=code`
|
|
156
181
|
|
|
157
|
-
Shift+L cycles through the `ides` list configured in plugin options.
|
|
158
|
-
|
|
159
182
|
## Adding a New IDE
|
|
160
183
|
|
|
161
184
|
1. Extend `LocatorIde` and `IDE_ORDER` in `src/shared/index.ts`
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { nextClickTarget, parseSourceLocation, resolveTheme } from '../shared/index.js';
|
|
1
|
+
import { nextClickTarget, nextIde, parseSourceLocation, resolveTheme } from '../shared/index.js';
|
|
2
2
|
import { findCssSource } from './css-source.js';
|
|
3
3
|
import { createLocatorOverlayUi } from './overlay.js';
|
|
4
|
-
import { cycleStoredIde, getStoredIde } from './preference.js';
|
|
5
4
|
const EMPTY_SOURCES = Object.freeze({
|
|
6
5
|
tsx: undefined,
|
|
7
6
|
css: undefined,
|
|
@@ -13,13 +12,13 @@ function getSourceEl(target, attribute, host) {
|
|
|
13
12
|
const el = target.closest(`[${attribute}]`);
|
|
14
13
|
return el instanceof HTMLElement ? el : null;
|
|
15
14
|
}
|
|
16
|
-
async function openSourceInEditor(source, config) {
|
|
15
|
+
async function openSourceInEditor(source, config, activeIde) {
|
|
17
16
|
const loc = parseSourceLocation(source);
|
|
18
17
|
const params = new URLSearchParams({
|
|
19
18
|
file: loc.file,
|
|
20
19
|
line: loc.line,
|
|
21
20
|
col: loc.col,
|
|
22
|
-
ide:
|
|
21
|
+
ide: activeIde,
|
|
23
22
|
});
|
|
24
23
|
await fetch(`${config.endpoint}?${params.toString()}`);
|
|
25
24
|
}
|
|
@@ -34,7 +33,8 @@ function resolveOpenSource(sources) {
|
|
|
34
33
|
export function startPickController(root, host, config) {
|
|
35
34
|
let pickMode = false;
|
|
36
35
|
let sources = EMPTY_SOURCES;
|
|
37
|
-
|
|
36
|
+
let activeIde = config.ides[0] ?? 'auto';
|
|
37
|
+
const ui = createLocatorOverlayUi(root, () => setPickMode(!pickMode), resolveTheme(config.theme), () => activeIde);
|
|
38
38
|
function setPickMode(active) {
|
|
39
39
|
pickMode = active;
|
|
40
40
|
ui.setPickActive(active);
|
|
@@ -68,10 +68,10 @@ export function startPickController(root, host, config) {
|
|
|
68
68
|
}
|
|
69
69
|
if (!e.shiftKey || e.key !== 'L')
|
|
70
70
|
return;
|
|
71
|
-
|
|
71
|
+
activeIde = nextIde(activeIde, config.ides);
|
|
72
72
|
if (!pickMode)
|
|
73
73
|
ui.refreshBadgeLabel();
|
|
74
|
-
ui.flashMessage(`IDE: ${
|
|
74
|
+
ui.flashMessage(`IDE: ${activeIde}`);
|
|
75
75
|
};
|
|
76
76
|
const onClick = async (e) => {
|
|
77
77
|
if (!pickMode || host.contains(e.target))
|
|
@@ -86,7 +86,7 @@ export function startPickController(root, host, config) {
|
|
|
86
86
|
ui.flashMessage('No source for this element');
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
|
-
await openSourceInEditor(openSource, config);
|
|
89
|
+
await openSourceInEditor(openSource, config, activeIde);
|
|
90
90
|
sources = { ...sources, clickTarget: nextClickTarget(sources.clickTarget, !!sources.css) };
|
|
91
91
|
ui.showSourceTooltip(el, sources.tsx, sources.css, sources.clickTarget, e.clientX, e.clientY);
|
|
92
92
|
};
|
package/dist/client/overlay.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ClickTarget, LocatorTheme } from '../shared/index.js';
|
|
2
|
-
export declare function createLocatorOverlayUi(root: ShadowRoot, onTogglePick: () => void, theme: LocatorTheme): {
|
|
1
|
+
import type { ClickTarget, LocatorIde, LocatorTheme } from '../shared/index.js';
|
|
2
|
+
export declare function createLocatorOverlayUi(root: ShadowRoot, onTogglePick: () => void, theme: LocatorTheme, getActiveIde: () => LocatorIde): {
|
|
3
3
|
mountBadge: () => void;
|
|
4
4
|
setPickActive: (active: boolean) => void;
|
|
5
5
|
refreshBadgeLabel: () => void;
|
package/dist/client/overlay.js
CHANGED
|
@@ -6,7 +6,7 @@ const TOOLTIP_CURSOR_OFFSET = 16;
|
|
|
6
6
|
const FLASH_DURATION_MS = 1500;
|
|
7
7
|
const FLASH_HORIZONTAL_OFFSET = 80;
|
|
8
8
|
const FLASH_BOTTOM_OFFSET = 80;
|
|
9
|
-
export function createLocatorOverlayUi(root, onTogglePick, theme) {
|
|
9
|
+
export function createLocatorOverlayUi(root, onTogglePick, theme, getActiveIde) {
|
|
10
10
|
let activeEl = null;
|
|
11
11
|
let flashTimeout = null;
|
|
12
12
|
let badgeEl = null;
|
|
@@ -70,20 +70,20 @@ export function createLocatorOverlayUi(root, onTogglePick, theme) {
|
|
|
70
70
|
document.body.style.cursor = active ? 'crosshair' : '';
|
|
71
71
|
if (!badgeEl)
|
|
72
72
|
return;
|
|
73
|
-
badgeEl.textContent = badgeLabel(active);
|
|
73
|
+
badgeEl.textContent = badgeLabel(active, getActiveIde());
|
|
74
74
|
applyBadgeColors(active);
|
|
75
75
|
if (!active)
|
|
76
76
|
removeTooltip();
|
|
77
77
|
};
|
|
78
78
|
const refreshBadgeLabel = () => {
|
|
79
79
|
if (badgeEl)
|
|
80
|
-
badgeEl.textContent = badgeLabel(false);
|
|
80
|
+
badgeEl.textContent = badgeLabel(false, getActiveIde());
|
|
81
81
|
};
|
|
82
82
|
const mountBadge = () => {
|
|
83
83
|
badgeEl = document.createElement('button');
|
|
84
84
|
badgeEl.id = UI_IDS.badge;
|
|
85
85
|
badgeEl.type = 'button';
|
|
86
|
-
badgeEl.textContent = badgeLabel(false);
|
|
86
|
+
badgeEl.textContent = badgeLabel(false, getActiveIde());
|
|
87
87
|
Object.assign(badgeEl.style, LAYOUT.badge, {
|
|
88
88
|
background: theme.badgeBackground,
|
|
89
89
|
color: theme.badgeText,
|
|
@@ -1,5 +1,2 @@
|
|
|
1
1
|
import type { LocatorIde } from '../shared/index.js';
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function setStoredIde(ide: LocatorIde): void;
|
|
4
|
-
export declare function cycleStoredIde(order: LocatorIde[]): LocatorIde;
|
|
5
|
-
export declare function badgeLabel(picking: boolean): string;
|
|
2
|
+
export declare function badgeLabel(picking: boolean, activeIde: LocatorIde): string;
|
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
import { DEFAULT_IDE, STORAGE_KEY, isLocatorIde, nextIde } from '../shared/index.js';
|
|
2
|
-
export function getStoredIde() {
|
|
3
|
-
const stored = localStorage.getItem(STORAGE_KEY) ?? DEFAULT_IDE;
|
|
4
|
-
return isLocatorIde(stored) ? stored : DEFAULT_IDE;
|
|
5
|
-
}
|
|
6
|
-
export function setStoredIde(ide) {
|
|
7
|
-
localStorage.setItem(STORAGE_KEY, ide);
|
|
8
|
-
}
|
|
9
|
-
export function cycleStoredIde(order) {
|
|
10
|
-
const next = nextIde(getStoredIde(), order);
|
|
11
|
-
setStoredIde(next);
|
|
12
|
-
return next;
|
|
13
|
-
}
|
|
14
1
|
const BADGE_PICKING_HINT = 'Esc to cancel';
|
|
15
2
|
const BADGE_IDLE_HINT = 'click to pick';
|
|
16
|
-
export function badgeLabel(picking) {
|
|
17
|
-
const ide = getStoredIde();
|
|
3
|
+
export function badgeLabel(picking, activeIde) {
|
|
18
4
|
if (picking)
|
|
19
|
-
return `Pick element (${
|
|
20
|
-
return `Source Locator (${
|
|
5
|
+
return `Pick element (${activeIde}) — ${BADGE_PICKING_HINT}`;
|
|
6
|
+
return `Source Locator (${activeIde}) — ${BADGE_IDLE_HINT}`;
|
|
21
7
|
}
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { LocatorTheme, LocatorThemeInput, LocatorThemeOverride, LocatorThemePreset, } from './theme.js';
|
|
2
2
|
export { resolveTheme } from './theme.js';
|
|
3
|
-
export type LocatorIde = 'cursor' | 'vscode' | 'webstorm';
|
|
3
|
+
export type LocatorIde = 'auto' | 'cursor' | 'vscode' | 'webstorm';
|
|
4
4
|
export type SourceLocation = {
|
|
5
5
|
file: string;
|
|
6
6
|
line: string;
|
|
@@ -9,10 +9,10 @@ export type SourceLocation = {
|
|
|
9
9
|
export type ClickTarget = 'tsx' | 'css';
|
|
10
10
|
export declare const SOURCE_ATTR = "data-source";
|
|
11
11
|
export declare const OPEN_ENDPOINT = "/__open-in-editor";
|
|
12
|
-
export declare const STORAGE_KEY = "locator-ide";
|
|
13
12
|
export declare const DEFAULT_IDE: LocatorIde;
|
|
14
13
|
export declare const IDE_ORDER: LocatorIde[];
|
|
15
14
|
export declare function isLocatorIde(value: string): value is LocatorIde;
|
|
15
|
+
export declare function resolveIde(value: string, allowed: LocatorIde[]): LocatorIde;
|
|
16
16
|
export declare function nextIde(current: LocatorIde, order?: LocatorIde[]): LocatorIde;
|
|
17
17
|
export declare function parseSourceLocation(raw: string): SourceLocation;
|
|
18
18
|
export declare function formatSourceLocation(loc: SourceLocation): string;
|
package/dist/shared/index.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
export { resolveTheme } from './theme.js';
|
|
2
2
|
export const SOURCE_ATTR = 'data-source';
|
|
3
3
|
export const OPEN_ENDPOINT = '/__open-in-editor';
|
|
4
|
-
export const
|
|
5
|
-
export const
|
|
6
|
-
export const IDE_ORDER = ['cursor', 'vscode', 'webstorm'];
|
|
4
|
+
export const DEFAULT_IDE = 'auto';
|
|
5
|
+
export const IDE_ORDER = ['auto', 'cursor', 'vscode', 'webstorm'];
|
|
7
6
|
export function isLocatorIde(value) {
|
|
8
7
|
return IDE_ORDER.includes(value);
|
|
9
8
|
}
|
|
9
|
+
export function resolveIde(value, allowed) {
|
|
10
|
+
const fallback = allowed[0] ?? DEFAULT_IDE;
|
|
11
|
+
if (!isLocatorIde(value))
|
|
12
|
+
return fallback;
|
|
13
|
+
if (!allowed.includes(value))
|
|
14
|
+
return fallback;
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
10
17
|
export function nextIde(current, order = IDE_ORDER) {
|
|
11
18
|
const index = order.indexOf(current);
|
|
12
19
|
const nextIndex = (index + 1) % order.length;
|
package/dist/vite/editors.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { SourceLocation } from '../shared/index.js';
|
|
2
|
-
export declare function openInEditor(loc: SourceLocation, ideParam: string): void;
|
|
1
|
+
import type { LocatorIde, SourceLocation } from '../shared/index.js';
|
|
2
|
+
export declare function openInEditor(loc: SourceLocation, ideParam: string, allowed: LocatorIde[]): void;
|
package/dist/vite/editors.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import launch from 'launch-editor';
|
|
2
|
-
import {
|
|
3
|
-
export function openInEditor(loc, ideParam) {
|
|
4
|
-
const ide =
|
|
2
|
+
import { resolveIde } from '../shared/index.js';
|
|
3
|
+
export function openInEditor(loc, ideParam, allowed) {
|
|
4
|
+
const ide = resolveIde(ideParam, allowed);
|
|
5
5
|
const spec = `${loc.file}:${loc.line}:${loc.col}`;
|
|
6
|
+
if (ide === 'auto') {
|
|
7
|
+
launch(spec);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
6
10
|
launch(spec, ide);
|
|
7
11
|
}
|
package/dist/vite/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { isAbsolute, resolve } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import {
|
|
4
|
+
import { IDE_ORDER, OPEN_ENDPOINT, SOURCE_ATTR } from '../shared/index.js';
|
|
5
5
|
import { babelPluginAddSourceAttr } from './babel-plugin.js';
|
|
6
6
|
import { openInEditor } from './editors.js';
|
|
7
7
|
const VIRTUAL_CLIENT_ID = 'virtual:source-locator-client';
|
|
@@ -16,13 +16,13 @@ function resolveOptions(options = {}) {
|
|
|
16
16
|
theme: options.theme,
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
-
function readQuery(url) {
|
|
19
|
+
function readQuery(url, defaultIde) {
|
|
20
20
|
const parsed = new URL(url, 'http://localhost');
|
|
21
21
|
return {
|
|
22
22
|
file: parsed.searchParams.get('file'),
|
|
23
23
|
line: parsed.searchParams.get('line') ?? '1',
|
|
24
24
|
col: parsed.searchParams.get('col') ?? '1',
|
|
25
|
-
ide: parsed.searchParams.get('ide') ??
|
|
25
|
+
ide: parsed.searchParams.get('ide') ?? defaultIde,
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
function resolveFilePath(file, root) {
|
|
@@ -56,7 +56,7 @@ function sourceLocator(options = {}) {
|
|
|
56
56
|
},
|
|
57
57
|
configureServer(server) {
|
|
58
58
|
server.middlewares.use(config.endpoint, (req, res) => {
|
|
59
|
-
const { file, line, col, ide } = readQuery(req.url ?? '');
|
|
59
|
+
const { file, line, col, ide } = readQuery(req.url ?? '', config.ides[0] ?? 'auto');
|
|
60
60
|
if (!file) {
|
|
61
61
|
res.writeHead(400);
|
|
62
62
|
res.end('missing file');
|
|
@@ -69,7 +69,7 @@ function sourceLocator(options = {}) {
|
|
|
69
69
|
res.end('file not found');
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
|
-
openInEditor({ file: resolvedFile, line, col }, ide);
|
|
72
|
+
openInEditor({ file: resolvedFile, line, col }, ide, config.ides);
|
|
73
73
|
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
74
74
|
res.end('ok');
|
|
75
75
|
}
|