Skip to content

Commit 5c08507

Browse files
committed
Fix for windows and try and reduce bundle impact
1 parent ecb4111 commit 5c08507

4 files changed

Lines changed: 79 additions & 39 deletions

File tree

packages/core/src/utils/debug-ids.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { DebugImage } from '../types-hoist/debugMeta';
22
import type { StackParser } from '../types-hoist/stacktrace';
3+
import { normalizeStackTracePath } from './stacktrace';
34
import { GLOBAL_OBJ } from './worldwide';
45

56
type StackString = string;
@@ -10,6 +11,17 @@ let lastSentryKeysCount: number | undefined;
1011
let lastNativeKeysCount: number | undefined;
1112
let cachedFilenameDebugIds: Record<string, string> | undefined;
1213

14+
/**
15+
* Clears the cached debug ID mappings.
16+
* Useful for testing or when the global debug ID state changes.
17+
*/
18+
export function clearDebugIdCache(): void {
19+
parsedStackResults = undefined;
20+
lastSentryKeysCount = undefined;
21+
lastNativeKeysCount = undefined;
22+
cachedFilenameDebugIds = undefined;
23+
}
24+
1325
/**
1426
* Returns a map of filenames to debug identifiers.
1527
* Supports both proprietary _sentryDebugIds and native _debugIds (e.g., from Vercel) formats.
@@ -101,8 +113,8 @@ export function getDebugImagesForResources(
101113

102114
const images: DebugImage[] = [];
103115
for (const path of resource_paths) {
104-
if (path) {
105-
const normalizedPath = path.startsWith('file://') ? path.slice(7) : path;
116+
const normalizedPath = normalizeStackTracePath(path);
117+
if (normalizedPath) {
106118
if (filenameDebugIdMap[normalizedPath]) {
107119
images.push({
108120
type: 'sourcemap',

packages/core/src/utils/node-stack-trace.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// THE SOFTWARE.
2323

2424
import type { StackLineParser, StackLineParserFn } from '../types-hoist/stacktrace';
25-
import { UNKNOWN_FUNCTION } from './stacktrace';
25+
import { normalizeStackTracePath, UNKNOWN_FUNCTION } from './stacktrace';
2626

2727
export type GetModuleFn = (filename: string | undefined) => string | undefined;
2828

@@ -55,7 +55,6 @@ export function node(getModule?: GetModuleFn): StackLineParserFn {
5555
const FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+):(\d+):(\d+)?|([^)]+))\)?/;
5656
const DATA_URI_MATCH = /at (?:async )?(.+?) \(data:(.*?),/;
5757

58-
// eslint-disable-next-line complexity
5958
return (line: string) => {
6059
const dataUriMatch = line.match(DATA_URI_MATCH);
6160
if (dataUriMatch) {
@@ -109,14 +108,9 @@ export function node(getModule?: GetModuleFn): StackLineParserFn {
109108
functionName = typeName ? `${typeName}.${methodName}` : methodName;
110109
}
111110

112-
let filename = lineMatch[2]?.startsWith('file://') ? lineMatch[2].slice(7) : lineMatch[2];
111+
let filename = normalizeStackTracePath(lineMatch[2]);
113112
const isNative = lineMatch[5] === 'native';
114113

115-
// If it's a Windows path, trim the leading slash so that `/C:/foo` becomes `C:/foo`
116-
if (filename?.match(/\/[A-Z]:/)) {
117-
filename = filename.slice(1);
118-
}
119-
120114
if (!filename && lineMatch[5] && !isNative) {
121115
filename = lineMatch[5];
122116
}

packages/core/src/utils/stacktrace.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,15 @@ export function getVueInternalName(value: VueViewModel | VNode): string {
177177

178178
return isVNode ? '[VueVNode]' : '[VueViewModel]';
179179
}
180+
181+
/**
182+
* Normalizes stack line paths by removing file:// prefix and leading slashes for Windows paths
183+
*/
184+
export function normalizeStackTracePath(path: string | undefined): string | undefined {
185+
let filename = path?.startsWith('file://') ? path.slice(7) : path;
186+
// If it's a Windows path, trim the leading slash so that `/C:/foo` becomes `C:/foo`
187+
if (filename?.match(/\/[A-Z]:/)) {
188+
filename = filename.slice(1);
189+
}
190+
return filename;
191+
}

packages/core/test/lib/utils/debug-ids.test.ts

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
import { beforeEach, describe, expect, it } from 'vitest';
2-
import type { StackParser } from '../../../src/types-hoist/stacktrace';
3-
import { getDebugImagesForResources, getFilenameToDebugIdMap } from '../../../src/utils/debug-ids';
2+
import { nodeStackLineParser } from '../../../src';
3+
import { clearDebugIdCache, getDebugImagesForResources, getFilenameToDebugIdMap } from '../../../src/utils/debug-ids';
4+
import { createStackParser } from '../../../src/utils/stacktrace';
45

5-
describe('getDebugImagesForResources', () => {
6-
const mockStackParser: StackParser = (stack: string) => {
7-
// Simple mock that extracts filename from a stack string
8-
const match = stack.match(/at .* \((.*?):\d+:\d+\)/);
9-
if (match) {
10-
return [{ filename: match[1], function: 'mockFunction', lineno: 1, colno: 1 }];
11-
}
12-
return [];
13-
};
6+
const nodeStackParser = createStackParser(nodeStackLineParser());
147

8+
describe('getDebugImagesForResources', () => {
159
beforeEach(() => {
1610
// Clear any existing debug ID maps
1711
delete (globalThis as any)._sentryDebugIds;
1812
delete (globalThis as any)._debugIds;
13+
clearDebugIdCache();
1914
});
2015

2116
it('should return debug images for resources without file:// prefix', () => {
@@ -25,7 +20,7 @@ describe('getDebugImagesForResources', () => {
2520
};
2621

2722
const resources = ['/var/task/index.js'];
28-
const images = getDebugImagesForResources(mockStackParser, resources);
23+
const images = getDebugImagesForResources(nodeStackParser, resources);
2924

3025
expect(images).toHaveLength(1);
3126
expect(images[0]).toEqual({
@@ -43,7 +38,7 @@ describe('getDebugImagesForResources', () => {
4338

4439
// V8 profiler returns resources WITH file:// prefix
4540
const resources = ['file:///var/task/index.js'];
46-
const images = getDebugImagesForResources(mockStackParser, resources);
41+
const images = getDebugImagesForResources(nodeStackParser, resources);
4742

4843
expect(images).toHaveLength(1);
4944
expect(images[0]).toEqual({
@@ -60,7 +55,7 @@ describe('getDebugImagesForResources', () => {
6055
};
6156

6257
const resources = ['file:///var/task/index.js', '/var/task/utils.js'];
63-
const images = getDebugImagesForResources(mockStackParser, resources);
58+
const images = getDebugImagesForResources(nodeStackParser, resources);
6459

6560
expect(images).toHaveLength(2);
6661
expect(images[0]).toEqual({
@@ -81,14 +76,14 @@ describe('getDebugImagesForResources', () => {
8176
};
8277

8378
const resources = ['file:///var/task/other.js'];
84-
const images = getDebugImagesForResources(mockStackParser, resources);
79+
const images = getDebugImagesForResources(nodeStackParser, resources);
8580

8681
expect(images).toHaveLength(0);
8782
});
8883

8984
it('should return empty array when no debug IDs are registered', () => {
9085
const resources = ['file:///var/task/index.js'];
91-
const images = getDebugImagesForResources(mockStackParser, resources);
86+
const images = getDebugImagesForResources(nodeStackParser, resources);
9287

9388
expect(images).toHaveLength(0);
9489
});
@@ -99,28 +94,55 @@ describe('getDebugImagesForResources', () => {
9994
};
10095

10196
const resources: string[] = [];
102-
const images = getDebugImagesForResources(mockStackParser, resources);
97+
const images = getDebugImagesForResources(nodeStackParser, resources);
10398

10499
expect(images).toHaveLength(0);
105100
});
101+
102+
it('should handle Windows paths with file:// prefix', () => {
103+
// Stack parser normalizes Windows paths: file:///C:/foo.js -> C:/foo.js
104+
(globalThis as any)._sentryDebugIds = {
105+
'at mockFunction (C:/Users/dev/project/index.js:1:1)': 'debug-id-win-123',
106+
};
107+
108+
// V8 profiler returns Windows paths with file:// prefix
109+
const resources = ['file:///C:/Users/dev/project/index.js'];
110+
const images = getDebugImagesForResources(nodeStackParser, resources);
111+
112+
expect(images).toHaveLength(1);
113+
expect(images[0]).toEqual({
114+
type: 'sourcemap',
115+
code_file: 'file:///C:/Users/dev/project/index.js',
116+
debug_id: 'debug-id-win-123',
117+
});
118+
});
119+
120+
it('should handle Windows paths without file:// prefix', () => {
121+
(globalThis as any)._sentryDebugIds = {
122+
'at mockFunction (C:/Users/dev/project/index.js:1:1)': 'debug-id-win-123',
123+
};
124+
125+
const resources = ['C:/Users/dev/project/index.js'];
126+
const images = getDebugImagesForResources(nodeStackParser, resources);
127+
128+
expect(images).toHaveLength(1);
129+
expect(images[0]).toEqual({
130+
type: 'sourcemap',
131+
code_file: 'C:/Users/dev/project/index.js',
132+
debug_id: 'debug-id-win-123',
133+
});
134+
});
106135
});
107136

108137
describe('getFilenameToDebugIdMap', () => {
109-
const mockStackParser: StackParser = (stack: string) => {
110-
const match = stack.match(/at .* \((.*?):\d+:\d+\)/);
111-
if (match) {
112-
return [{ filename: match[1], function: 'mockFunction', lineno: 1, colno: 1 }];
113-
}
114-
return [];
115-
};
116-
117138
beforeEach(() => {
118139
delete (globalThis as any)._sentryDebugIds;
119140
delete (globalThis as any)._debugIds;
141+
clearDebugIdCache();
120142
});
121143

122144
it('should return empty object when no debug IDs are registered', () => {
123-
const map = getFilenameToDebugIdMap(mockStackParser);
145+
const map = getFilenameToDebugIdMap(nodeStackParser);
124146
expect(map).toEqual({});
125147
});
126148

@@ -130,7 +152,7 @@ describe('getFilenameToDebugIdMap', () => {
130152
'at anotherFunction (/var/task/utils.js:10:5)': 'debug-id-456',
131153
};
132154

133-
const map = getFilenameToDebugIdMap(mockStackParser);
155+
const map = getFilenameToDebugIdMap(nodeStackParser);
134156

135157
expect(map).toEqual({
136158
'/var/task/index.js': 'debug-id-123',
@@ -143,7 +165,7 @@ describe('getFilenameToDebugIdMap', () => {
143165
'at mockFunction (/var/task/index.js:1:1)': 'native-debug-id-123',
144166
};
145167

146-
const map = getFilenameToDebugIdMap(mockStackParser);
168+
const map = getFilenameToDebugIdMap(nodeStackParser);
147169

148170
expect(map).toEqual({
149171
'/var/task/index.js': 'native-debug-id-123',
@@ -158,7 +180,7 @@ describe('getFilenameToDebugIdMap', () => {
158180
'at mockFunction (/var/task/index.js:1:1)': 'native-debug-id',
159181
};
160182

161-
const map = getFilenameToDebugIdMap(mockStackParser);
183+
const map = getFilenameToDebugIdMap(nodeStackParser);
162184

163185
expect(map['/var/task/index.js']).toBe('native-debug-id');
164186
});

0 commit comments

Comments
 (0)