Skip to content

Commit d0e2293

Browse files
committed
do not transform files with manul middleware wrapping
1 parent 36f0ab9 commit d0e2293

File tree

2 files changed

+146
-1
lines changed

2 files changed

+146
-1
lines changed

packages/tanstackstart-react/src/vite/autoInstrumentMiddleware.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,16 @@ export function makeAutoInstrumentMiddlewarePlugin(options: AutoInstrumentMiddle
3131
return null;
3232
}
3333

34-
// only wrap requestMiddleware and functionMiddleware in createStart()
34+
// Only wrap requestMiddleware and functionMiddleware in createStart()
3535
if (!code.includes('createStart')) {
3636
return null;
3737
}
3838

39+
// Skip if the user already did some manual wrapping
40+
if (code.includes('wrapMiddlewaresWithSentry')) {
41+
return null;
42+
}
43+
3944
let transformed = code;
4045
let needsImport = false;
4146

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import type { Plugin } from 'vite';
2+
import { describe, expect, it } from 'vitest';
3+
import {
4+
arrayToObjectShorthand,
5+
makeAutoInstrumentMiddlewarePlugin,
6+
} from '../../src/vite/autoInstrumentMiddleware';
7+
8+
type PluginWithTransform = Plugin & {
9+
transform: (code: string, id: string) => { code: string; map: null } | null;
10+
};
11+
12+
describe('makeAutoInstrumentMiddlewarePlugin', () => {
13+
const createStartFile = `
14+
import { createStart } from '@tanstack/react-start';
15+
import { authMiddleware, loggingMiddleware } from './middleware';
16+
17+
export const startInstance = createStart(() => ({
18+
requestMiddleware: [authMiddleware],
19+
functionMiddleware: [loggingMiddleware],
20+
}));
21+
`;
22+
23+
it('instruments a file with createStart and middleware arrays', () => {
24+
const plugin = makeAutoInstrumentMiddlewarePlugin() as PluginWithTransform;
25+
const result = plugin.transform(createStartFile, '/app/start.ts');
26+
27+
expect(result).not.toBeNull();
28+
expect(result!.code).toContain("import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react'");
29+
expect(result!.code).toContain('requestMiddleware: wrapMiddlewaresWithSentry({ authMiddleware })');
30+
expect(result!.code).toContain('functionMiddleware: wrapMiddlewaresWithSentry({ loggingMiddleware })');
31+
});
32+
33+
it('does not instrument files without createStart', () => {
34+
const plugin = makeAutoInstrumentMiddlewarePlugin() as PluginWithTransform;
35+
const code = `export const foo = 'bar';`;
36+
const result = plugin.transform(code, '/app/other.ts');
37+
38+
expect(result).toBeNull();
39+
});
40+
41+
it('does not instrument non-TS/JS files', () => {
42+
const plugin = makeAutoInstrumentMiddlewarePlugin() as PluginWithTransform;
43+
const result = plugin.transform(createStartFile, '/app/start.css');
44+
45+
expect(result).toBeNull();
46+
});
47+
48+
it('does not instrument when enabled is false', () => {
49+
const plugin = makeAutoInstrumentMiddlewarePlugin({ enabled: false }) as PluginWithTransform;
50+
const result = plugin.transform(createStartFile, '/app/start.ts');
51+
52+
expect(result).toBeNull();
53+
});
54+
55+
it('wraps single middleware entry correctly', () => {
56+
const plugin = makeAutoInstrumentMiddlewarePlugin() as PluginWithTransform;
57+
const code = `
58+
import { createStart } from '@tanstack/react-start';
59+
createStart(() => ({ requestMiddleware: [singleMiddleware] }));
60+
`;
61+
const result = plugin.transform(code, '/app/start.ts');
62+
63+
expect(result!.code).toContain('requestMiddleware: wrapMiddlewaresWithSentry({ singleMiddleware })');
64+
});
65+
66+
it('wraps multiple middleware entries correctly', () => {
67+
const plugin = makeAutoInstrumentMiddlewarePlugin() as PluginWithTransform;
68+
const code = `
69+
import { createStart } from '@tanstack/react-start';
70+
createStart(() => ({ requestMiddleware: [a, b, c] }));
71+
`;
72+
const result = plugin.transform(code, '/app/start.ts');
73+
74+
expect(result!.code).toContain('requestMiddleware: wrapMiddlewaresWithSentry({ a, b, c })');
75+
});
76+
77+
it('does not wrap empty middleware arrays', () => {
78+
const plugin = makeAutoInstrumentMiddlewarePlugin() as PluginWithTransform;
79+
const code = `
80+
import { createStart } from '@tanstack/react-start';
81+
createStart(() => ({ requestMiddleware: [] }));
82+
`;
83+
const result = plugin.transform(code, '/app/start.ts');
84+
85+
expect(result).toBeNull();
86+
});
87+
88+
it('does not wrap if middleware contains function calls', () => {
89+
const plugin = makeAutoInstrumentMiddlewarePlugin() as PluginWithTransform;
90+
const code = `
91+
import { createStart } from '@tanstack/react-start';
92+
createStart(() => ({ requestMiddleware: [getMiddleware()] }));
93+
`;
94+
const result = plugin.transform(code, '/app/start.ts');
95+
96+
expect(result).toBeNull();
97+
});
98+
99+
it('does not instrument files that already use wrapMiddlewaresWithSentry', () => {
100+
const plugin = makeAutoInstrumentMiddlewarePlugin() as PluginWithTransform;
101+
const code = `
102+
import { createStart } from '@tanstack/react-start';
103+
import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';
104+
createStart(() => ({ requestMiddleware: wrapMiddlewaresWithSentry({ myMiddleware }) }));
105+
`;
106+
const result = plugin.transform(code, '/app/start.ts');
107+
108+
expect(result).toBeNull();
109+
});
110+
});
111+
112+
describe('arrayToObjectShorthand', () => {
113+
it('converts single identifier', () => {
114+
expect(arrayToObjectShorthand('foo')).toBe('{ foo }');
115+
});
116+
117+
it('converts multiple identifiers', () => {
118+
expect(arrayToObjectShorthand('foo, bar, baz')).toBe('{ foo, bar, baz }');
119+
});
120+
121+
it('handles whitespace', () => {
122+
expect(arrayToObjectShorthand(' foo , bar ')).toBe('{ foo, bar }');
123+
});
124+
125+
it('returns null for empty string', () => {
126+
expect(arrayToObjectShorthand('')).toBeNull();
127+
});
128+
129+
it('returns null for function calls', () => {
130+
expect(arrayToObjectShorthand('getMiddleware()')).toBeNull();
131+
});
132+
133+
it('returns null for spread syntax', () => {
134+
expect(arrayToObjectShorthand('...middlewares')).toBeNull();
135+
});
136+
137+
it('returns null for mixed valid and invalid', () => {
138+
expect(arrayToObjectShorthand('foo, bar(), baz')).toBeNull();
139+
});
140+
});

0 commit comments

Comments
 (0)