fixdog 0.0.1 → 0.0.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/LICENSE +21 -0
- package/README.md +80 -433
- package/dist/api/client.d.ts +74 -0
- package/dist/components/ConversationalInputReact.d.ts +26 -0
- package/dist/components/ElementInfoDisplayReact.d.ts +9 -0
- package/dist/components/FixdogSidebarReact.d.ts +29 -0
- package/dist/fiber.d.ts +9 -0
- package/dist/index.cjs.js +33 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +6 -158
- package/dist/index.esm.js +29 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/inspector-B4F5CBT7.cjs.js +1159 -0
- package/dist/inspector-B4F5CBT7.cjs.js.map +1 -0
- package/dist/inspector-BL2pNjn-.cjs.js +1173 -0
- package/dist/inspector-BL2pNjn-.cjs.js.map +1 -0
- package/dist/inspector-Bg6uSvk0.esm.js +1273 -0
- package/dist/inspector-Bg6uSvk0.esm.js.map +1 -0
- package/dist/inspector-BuOffbVc.cjs.js +1280 -0
- package/dist/inspector-BuOffbVc.cjs.js.map +1 -0
- package/dist/inspector-CNgFkZOU.esm.js +1185 -0
- package/dist/inspector-CNgFkZOU.esm.js.map +1 -0
- package/dist/inspector-CPF1N9dL.esm.js +1185 -0
- package/dist/inspector-CPF1N9dL.esm.js.map +1 -0
- package/dist/inspector-CPGK5Lg7.esm.js +1155 -0
- package/dist/inspector-CPGK5Lg7.esm.js.map +1 -0
- package/dist/inspector-CWcTSREy.cjs.js +1174 -0
- package/dist/inspector-CWcTSREy.cjs.js.map +1 -0
- package/dist/inspector-Cn_bl9Io.cjs.js +1189 -0
- package/dist/inspector-Cn_bl9Io.cjs.js.map +1 -0
- package/dist/inspector-D9DuXirp.cjs.js +1189 -0
- package/dist/inspector-D9DuXirp.cjs.js.map +1 -0
- package/dist/inspector-DQEtAjyM.esm.js +1129 -0
- package/dist/inspector-DQEtAjyM.esm.js.map +1 -0
- package/dist/inspector-DVlU9p44.cjs.js +1189 -0
- package/dist/inspector-DVlU9p44.cjs.js.map +1 -0
- package/dist/inspector-DaRVppX9.cjs.js +1134 -0
- package/dist/inspector-DaRVppX9.cjs.js.map +1 -0
- package/dist/inspector-huqtI2MD.esm.js +1170 -0
- package/dist/inspector-huqtI2MD.esm.js.map +1 -0
- package/dist/inspector-spoCY1tf.esm.js +1169 -0
- package/dist/inspector-spoCY1tf.esm.js.map +1 -0
- package/dist/inspector-tY1kJK5_.esm.js +1185 -0
- package/dist/inspector-tY1kJK5_.esm.js.map +1 -0
- package/dist/inspector.d.ts +43 -0
- package/dist/keyboard.d.ts +10 -0
- package/dist/overlay.d.ts +31 -0
- package/dist/react/InspectorProvider.d.ts +6 -0
- package/dist/react/index.cjs.js +32 -0
- package/dist/react/index.cjs.js.map +1 -0
- package/dist/react/index.esm.js +30 -0
- package/dist/react/index.esm.js.map +1 -0
- package/dist/sidebar/SidebarRuntime.d.ts +8 -0
- package/dist/sidebar-runtime.esm.js +2122 -0
- package/dist/sidebar-runtime.esm.js.map +1 -0
- package/dist/sidebar-runtime.iife.js +2991 -0
- package/dist/styles/sidebarStyles.d.ts +2 -0
- package/dist/styles.d.ts +8 -0
- package/dist/types/sidebar.d.ts +62 -0
- package/dist/types.d.ts +47 -0
- package/dist/utils/cookies.d.ts +10 -0
- package/dist/utils/devMode.d.ts +17 -0
- package/dist/utils/sessionStorage.d.ts +19 -0
- package/package.json +57 -40
- package/USAGE.md +0 -77
- package/dist/client/index.d.mts +0 -110
- package/dist/client/index.d.ts +0 -110
- package/dist/client/index.js +0 -1601
- package/dist/client/index.mjs +0 -1582
- package/dist/client/init.d.mts +0 -67
- package/dist/client/init.d.ts +0 -67
- package/dist/client/init.js +0 -1609
- package/dist/client/init.mjs +0 -1593
- package/dist/index.d.mts +0 -158
- package/dist/index.js +0 -1635
- package/dist/index.mjs +0 -1606
- package/src/api/client.ts +0 -141
- package/src/client/index.ts +0 -75
- package/src/client/init.tsx +0 -78
- package/src/components/ConversationalInputReact.tsx +0 -406
- package/src/components/ElementInfoDisplayReact.tsx +0 -84
- package/src/components/UiDogSidebarReact.tsx +0 -49
- package/src/element-detector.ts +0 -186
- package/src/index.ts +0 -228
- package/src/instrument.ts +0 -171
- package/src/sidebar-initializer.ts +0 -171
- package/src/source-resolver.ts +0 -121
- package/src/styles/sidebarStyles.ts +0 -597
- package/src/types/css.d.ts +0 -9
- package/src/types/sidebar.ts +0 -56
- package/src/types.ts +0 -119
- package/tsconfig.json +0 -23
- package/tsup.config.ts +0 -40
package/src/instrument.ts
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bippy instrumentation setup for React fiber inspection
|
|
3
|
-
*
|
|
4
|
-
* Bippy hooks into React's DevTools API (window.__REACT_DEVTOOLS_GLOBAL_HOOK__)
|
|
5
|
-
* to intercept fiber tree data and extract source location information.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
instrument,
|
|
10
|
-
secure,
|
|
11
|
-
isCompositeFiber,
|
|
12
|
-
isHostFiber,
|
|
13
|
-
traverseFiber,
|
|
14
|
-
getDisplayName,
|
|
15
|
-
getFiberFromHostInstance,
|
|
16
|
-
} from "bippy";
|
|
17
|
-
import { getSource } from "bippy/source";
|
|
18
|
-
import type { SourceLocation } from "./types";
|
|
19
|
-
|
|
20
|
-
let isInstrumented = false;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Setup Bippy instrumentation to hook into React's internals
|
|
24
|
-
* This must be called BEFORE React loads (via instrumentation-client.ts)
|
|
25
|
-
*/
|
|
26
|
-
export function setupBippyInstrumentation(): void {
|
|
27
|
-
if (isInstrumented) return;
|
|
28
|
-
if (typeof window === "undefined") return;
|
|
29
|
-
|
|
30
|
-
isInstrumented = true;
|
|
31
|
-
|
|
32
|
-
instrument(
|
|
33
|
-
secure({
|
|
34
|
-
onCommitFiberRoot: (_rendererID, _fiberRoot) => {
|
|
35
|
-
// Called when React commits a render
|
|
36
|
-
// We can use this for additional tracking if needed
|
|
37
|
-
},
|
|
38
|
-
})
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Get source location from a DOM element by traversing its React fiber
|
|
44
|
-
*/
|
|
45
|
-
export async function getSourceFromElement(
|
|
46
|
-
element: Element
|
|
47
|
-
): Promise<SourceLocation | null> {
|
|
48
|
-
try {
|
|
49
|
-
// Get the fiber associated with this DOM element
|
|
50
|
-
const fiber = getFiberFromHostInstance(element);
|
|
51
|
-
|
|
52
|
-
if (!fiber) {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Try to get source from the fiber
|
|
57
|
-
const source = await getSource(fiber);
|
|
58
|
-
|
|
59
|
-
if (source && source.fileName) {
|
|
60
|
-
// Filter out node_modules and internal files
|
|
61
|
-
if (
|
|
62
|
-
source.fileName.includes("node_modules") ||
|
|
63
|
-
source.fileName.includes("react-dom") ||
|
|
64
|
-
source.fileName.includes("react/")
|
|
65
|
-
) {
|
|
66
|
-
// Try parent fibers to find user code
|
|
67
|
-
return await findUserSourceFromFiber(fiber);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
fileName: source.fileName,
|
|
72
|
-
lineNumber: source.lineNumber ?? 1,
|
|
73
|
-
columnNumber: source.columnNumber ?? 1,
|
|
74
|
-
functionName: source.functionName ?? undefined,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Fallback: traverse up the fiber tree to find source
|
|
79
|
-
return await findUserSourceFromFiber(fiber);
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.warn("[UiDog Next] Error getting source from element:", error);
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Traverse up the fiber tree to find the first user-code source
|
|
88
|
-
*/
|
|
89
|
-
async function findUserSourceFromFiber(
|
|
90
|
-
startFiber: any
|
|
91
|
-
): Promise<SourceLocation | null> {
|
|
92
|
-
let result: SourceLocation | null = null;
|
|
93
|
-
|
|
94
|
-
// Traverse upward through the fiber tree
|
|
95
|
-
traverseFiber(
|
|
96
|
-
startFiber,
|
|
97
|
-
async (fiber) => {
|
|
98
|
-
// Only check composite fibers (components, not host elements)
|
|
99
|
-
if (isCompositeFiber(fiber)) {
|
|
100
|
-
try {
|
|
101
|
-
const source = await getSource(fiber);
|
|
102
|
-
|
|
103
|
-
if (source && source.fileName) {
|
|
104
|
-
// Skip internal/library code
|
|
105
|
-
if (
|
|
106
|
-
!source.fileName.includes("node_modules") &&
|
|
107
|
-
!source.fileName.includes("react-dom") &&
|
|
108
|
-
!source.fileName.includes("react/")
|
|
109
|
-
) {
|
|
110
|
-
result = {
|
|
111
|
-
fileName: source.fileName,
|
|
112
|
-
lineNumber: source.lineNumber ?? 1,
|
|
113
|
-
columnNumber: source.columnNumber ?? 1,
|
|
114
|
-
functionName: source.functionName ?? getDisplayName(fiber) ?? undefined,
|
|
115
|
-
};
|
|
116
|
-
return true; // Stop traversal
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
} catch {
|
|
120
|
-
// Continue to next fiber
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return false; // Continue traversal
|
|
124
|
-
},
|
|
125
|
-
true // Traverse upward (toward root)
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
return result;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Get component name from a fiber
|
|
133
|
-
*/
|
|
134
|
-
export function getComponentNameFromFiber(fiber: any): string {
|
|
135
|
-
if (!fiber) return "Unknown";
|
|
136
|
-
|
|
137
|
-
// Try to get display name directly
|
|
138
|
-
const displayName = getDisplayName(fiber);
|
|
139
|
-
if (displayName && displayName !== "Unknown") {
|
|
140
|
-
return displayName;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Traverse up to find the nearest named component
|
|
144
|
-
let componentName = "Unknown";
|
|
145
|
-
|
|
146
|
-
traverseFiber(
|
|
147
|
-
fiber,
|
|
148
|
-
(f) => {
|
|
149
|
-
if (isCompositeFiber(f)) {
|
|
150
|
-
const name = getDisplayName(f);
|
|
151
|
-
if (name && name !== "Unknown") {
|
|
152
|
-
componentName = name;
|
|
153
|
-
return true; // Stop traversal
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return false;
|
|
157
|
-
},
|
|
158
|
-
true // Traverse upward
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
return componentName;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Re-export useful bippy utilities
|
|
165
|
-
export {
|
|
166
|
-
isCompositeFiber,
|
|
167
|
-
isHostFiber,
|
|
168
|
-
traverseFiber,
|
|
169
|
-
getDisplayName,
|
|
170
|
-
getFiberFromHostInstance,
|
|
171
|
-
};
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sidebar initializer - mounts the UiDog sidebar in a shadow DOM for style isolation
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { createRoot, Root } from "react-dom/client";
|
|
6
|
-
import { createElement } from "react";
|
|
7
|
-
import { UiDogSidebarReact } from "./components/UiDogSidebarReact";
|
|
8
|
-
import sidebarStyles from "./styles/sidebarStyles";
|
|
9
|
-
import type { ElementInfo, SidebarConfig } from "./types";
|
|
10
|
-
|
|
11
|
-
let sidebarRoot: Root | null = null;
|
|
12
|
-
let sidebarContainer: HTMLElement | null = null;
|
|
13
|
-
let shadowRoot: ShadowRoot | null = null;
|
|
14
|
-
let config: SidebarConfig = { apiEndpoint: "https://api.ui.dog" };
|
|
15
|
-
|
|
16
|
-
// Current sidebar state
|
|
17
|
-
let currentState: {
|
|
18
|
-
isOpen: boolean;
|
|
19
|
-
elementInfo: ElementInfo | null;
|
|
20
|
-
editorUrl: string;
|
|
21
|
-
} = {
|
|
22
|
-
isOpen: false,
|
|
23
|
-
elementInfo: null,
|
|
24
|
-
editorUrl: "",
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Initialize the sidebar with configuration
|
|
29
|
-
*/
|
|
30
|
-
export function initializeSidebar(sidebarConfig: SidebarConfig): void {
|
|
31
|
-
if (typeof window === "undefined") return;
|
|
32
|
-
|
|
33
|
-
config = sidebarConfig;
|
|
34
|
-
|
|
35
|
-
// Check if already initialized
|
|
36
|
-
if (document.getElementById("uidog-next-sidebar-root")) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Create container
|
|
41
|
-
sidebarContainer = document.createElement("div");
|
|
42
|
-
sidebarContainer.id = "uidog-next-sidebar-root";
|
|
43
|
-
document.body.appendChild(sidebarContainer);
|
|
44
|
-
|
|
45
|
-
// Create shadow DOM for style isolation
|
|
46
|
-
shadowRoot = sidebarContainer.attachShadow({ mode: "open" });
|
|
47
|
-
|
|
48
|
-
// Inject styles
|
|
49
|
-
const styleElement = document.createElement("style");
|
|
50
|
-
styleElement.textContent = sidebarStyles;
|
|
51
|
-
shadowRoot.appendChild(styleElement);
|
|
52
|
-
|
|
53
|
-
// Create mount point
|
|
54
|
-
const mountPoint = document.createElement("div");
|
|
55
|
-
mountPoint.id = "uidog-sidebar-mount";
|
|
56
|
-
shadowRoot.appendChild(mountPoint);
|
|
57
|
-
|
|
58
|
-
// Create React root
|
|
59
|
-
sidebarRoot = createRoot(mountPoint);
|
|
60
|
-
|
|
61
|
-
// Initial render (empty)
|
|
62
|
-
render();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Render the sidebar based on current state
|
|
67
|
-
*/
|
|
68
|
-
function render(): void {
|
|
69
|
-
if (!sidebarRoot) return;
|
|
70
|
-
|
|
71
|
-
const { isOpen, elementInfo, editorUrl } = currentState;
|
|
72
|
-
|
|
73
|
-
if (!isOpen || !elementInfo) {
|
|
74
|
-
sidebarRoot.render(null);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
sidebarRoot.render(
|
|
79
|
-
createElement(UiDogSidebarReact, {
|
|
80
|
-
elementInfo,
|
|
81
|
-
editorUrl,
|
|
82
|
-
onClose: closeSidebar,
|
|
83
|
-
apiEndpoint: config.apiEndpoint,
|
|
84
|
-
})
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Open the sidebar with element information
|
|
90
|
-
*/
|
|
91
|
-
export function openSidebar(elementInfo: ElementInfo, editorUrl: string): void {
|
|
92
|
-
currentState = {
|
|
93
|
-
isOpen: true,
|
|
94
|
-
elementInfo,
|
|
95
|
-
editorUrl,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// Update global state for debugging
|
|
99
|
-
if (typeof window !== "undefined") {
|
|
100
|
-
window.__UIDOG_SIDEBAR__ = {
|
|
101
|
-
isOpen: true,
|
|
102
|
-
elementInfo,
|
|
103
|
-
editorUrl,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
render();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Close the sidebar
|
|
112
|
-
*/
|
|
113
|
-
export function closeSidebar(): void {
|
|
114
|
-
currentState = {
|
|
115
|
-
isOpen: false,
|
|
116
|
-
elementInfo: null,
|
|
117
|
-
editorUrl: "",
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// Update global state
|
|
121
|
-
if (typeof window !== "undefined") {
|
|
122
|
-
window.__UIDOG_SIDEBAR__ = {
|
|
123
|
-
isOpen: false,
|
|
124
|
-
elementInfo: null,
|
|
125
|
-
editorUrl: null,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
render();
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Check if the sidebar is currently open
|
|
134
|
-
*/
|
|
135
|
-
export function isSidebarOpen(): boolean {
|
|
136
|
-
return currentState.isOpen;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Get current sidebar state
|
|
141
|
-
*/
|
|
142
|
-
export function getSidebarState(): typeof currentState {
|
|
143
|
-
return { ...currentState };
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Cleanup sidebar (for testing or unmounting)
|
|
148
|
-
*/
|
|
149
|
-
export function cleanupSidebar(): void {
|
|
150
|
-
if (sidebarRoot) {
|
|
151
|
-
sidebarRoot.unmount();
|
|
152
|
-
sidebarRoot = null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (sidebarContainer && sidebarContainer.parentNode) {
|
|
156
|
-
sidebarContainer.parentNode.removeChild(sidebarContainer);
|
|
157
|
-
sidebarContainer = null;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
shadowRoot = null;
|
|
161
|
-
|
|
162
|
-
currentState = {
|
|
163
|
-
isOpen: false,
|
|
164
|
-
elementInfo: null,
|
|
165
|
-
editorUrl: "",
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
if (typeof window !== "undefined") {
|
|
169
|
-
delete window.__UIDOG_SIDEBAR__;
|
|
170
|
-
}
|
|
171
|
-
}
|
package/src/source-resolver.ts
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Source resolver - builds editor URLs from source location information
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { SourceLocation, EditorType } from "./types";
|
|
6
|
-
|
|
7
|
-
const EDITOR_SCHEMES: Record<EditorType, string> = {
|
|
8
|
-
vscode: "vscode://file/{path}:{line}:{column}",
|
|
9
|
-
"vscode-insiders": "vscode-insiders://file/{path}:{line}:{column}",
|
|
10
|
-
cursor: "cursor://file/{path}:{line}:{column}",
|
|
11
|
-
webstorm: "webstorm://open?file={path}&line={line}&column={column}",
|
|
12
|
-
atom: "atom://core/open/file?filename={path}&line={line}&column={column}",
|
|
13
|
-
sublime: "subl://open?url=file://{path}&line={line}&column={column}",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Build an editor URL from source location information
|
|
18
|
-
*/
|
|
19
|
-
export function buildEditorUrl(
|
|
20
|
-
source: SourceLocation,
|
|
21
|
-
editor: EditorType = "cursor",
|
|
22
|
-
projectPath: string = ""
|
|
23
|
-
): string {
|
|
24
|
-
const template = EDITOR_SCHEMES[editor] || EDITOR_SCHEMES.cursor;
|
|
25
|
-
|
|
26
|
-
// Normalize and build full path
|
|
27
|
-
let fullPath = normalizeFileName(source.fileName);
|
|
28
|
-
|
|
29
|
-
// If path is relative and we have a project path, make it absolute
|
|
30
|
-
if (projectPath && !fullPath.startsWith("/")) {
|
|
31
|
-
const normalizedProjectPath = projectPath.endsWith("/")
|
|
32
|
-
? projectPath.slice(0, -1)
|
|
33
|
-
: projectPath;
|
|
34
|
-
fullPath = `${normalizedProjectPath}/${fullPath}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return template
|
|
38
|
-
.replace("{path}", fullPath)
|
|
39
|
-
.replace("{line}", String(source.lineNumber || 1))
|
|
40
|
-
.replace("{column}", String(source.columnNumber || 1));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Normalize file name by removing bundler prefixes and query strings
|
|
45
|
-
*/
|
|
46
|
-
export function normalizeFileName(fileName: string): string {
|
|
47
|
-
if (!fileName) return "";
|
|
48
|
-
|
|
49
|
-
let normalized = fileName;
|
|
50
|
-
|
|
51
|
-
// Remove common bundler prefixes
|
|
52
|
-
const prefixPatterns = [
|
|
53
|
-
/^webpack:\/\/[^/]*\//,
|
|
54
|
-
/^webpack-internal:\/\/\//,
|
|
55
|
-
/^file:\/\//,
|
|
56
|
-
/^about:react/,
|
|
57
|
-
/^\.\//,
|
|
58
|
-
/^https?:\/\/localhost:\d+\//,
|
|
59
|
-
/^https?:\/\/[^/]+\/@fs\//,
|
|
60
|
-
/^https?:\/\/[^/]+\//,
|
|
61
|
-
/^\/@fs\//,
|
|
62
|
-
/^@fs\//,
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
for (const pattern of prefixPatterns) {
|
|
66
|
-
normalized = normalized.replace(pattern, "");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Remove query strings and hash fragments
|
|
70
|
-
normalized = normalized.split("?")[0].split("#")[0];
|
|
71
|
-
|
|
72
|
-
// Remove leading slashes if duplicated
|
|
73
|
-
normalized = normalized.replace(/^\/+/, "/");
|
|
74
|
-
|
|
75
|
-
return normalized;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Check if a file name represents actual source code (not bundled/internal)
|
|
80
|
-
*/
|
|
81
|
-
export function isSourceFile(fileName: string): boolean {
|
|
82
|
-
if (!fileName) return false;
|
|
83
|
-
|
|
84
|
-
const normalized = normalizeFileName(fileName);
|
|
85
|
-
|
|
86
|
-
// Exclude patterns
|
|
87
|
-
const excludePatterns = [
|
|
88
|
-
/node_modules/,
|
|
89
|
-
/react-dom/,
|
|
90
|
-
/^react\//,
|
|
91
|
-
/\.next\//,
|
|
92
|
-
/_next\//,
|
|
93
|
-
/webpack/,
|
|
94
|
-
/@vite\//,
|
|
95
|
-
/vite\/client/,
|
|
96
|
-
/\[eval\]/,
|
|
97
|
-
/<anonymous>/,
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
for (const pattern of excludePatterns) {
|
|
101
|
-
if (pattern.test(normalized)) {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Include patterns (common source file extensions)
|
|
107
|
-
const includeExtensions = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
|
|
108
|
-
|
|
109
|
-
return includeExtensions.some((ext) =>
|
|
110
|
-
normalized.toLowerCase().endsWith(ext)
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Get the file name without path for display
|
|
116
|
-
*/
|
|
117
|
-
export function getShortFileName(filePath: string): string {
|
|
118
|
-
const normalized = normalizeFileName(filePath);
|
|
119
|
-
const parts = normalized.split("/");
|
|
120
|
-
return parts[parts.length - 1] || normalized;
|
|
121
|
-
}
|