|
1 | 1 | /* eslint-disable @sentry-internal/sdk/no-optional-chaining */ |
| 2 | +import type { ExportNamedDeclaration } from '@babel/types'; |
2 | 3 | import * as fs from 'fs'; |
| 4 | +import { parseModule } from 'magicast'; |
3 | 5 | import * as path from 'path'; |
4 | 6 | import type { Plugin } from 'vite'; |
5 | 7 |
|
@@ -89,24 +91,50 @@ export function makeAutoInstrumentationPlugin(options: AutoInstrumentPluginOptio |
89 | 91 | */ |
90 | 92 | export async function canWrapLoad(id: string, debug: boolean): Promise<boolean> { |
91 | 93 | const code = (await fs.promises.readFile(id, 'utf8')).toString(); |
| 94 | + const mod = parseModule(code); |
92 | 95 |
|
93 | | - const codeWithoutComments = code.replace(/(\/\/.*| ?\/\*[^]*?\*\/)(,?)$/gm, ''); |
94 | | - |
95 | | - const hasSentryContent = codeWithoutComments.includes('@sentry/sveltekit'); |
96 | | - if (hasSentryContent) { |
| 96 | + const program = mod.$ast.type === 'Program' && mod.$ast; |
| 97 | + if (!program) { |
97 | 98 | // eslint-disable-next-line no-console |
98 | | - debug && console.log(`Skipping wrapping ${id} because it already contains Sentry code`); |
| 99 | + debug && console.log(`Skipping wrapping ${id} because it doesn't contain valid JavaScript or TypeScript`); |
| 100 | + return false; |
99 | 101 | } |
100 | 102 |
|
101 | | - const hasLoadDeclaration = /((const|let|var|function)\s+load\s*(=|\(|:))|as\s+load\s*(,|})/gm.test( |
102 | | - codeWithoutComments, |
103 | | - ); |
| 103 | + const hasLoadDeclaration = program.body |
| 104 | + .filter((statement): statement is ExportNamedDeclaration => statement.type === 'ExportNamedDeclaration') |
| 105 | + .find(exportDecl => { |
| 106 | + // find `export const load = ...` |
| 107 | + if (exportDecl.declaration && exportDecl.declaration.type === 'VariableDeclaration') { |
| 108 | + const variableDeclarations = exportDecl.declaration.declarations; |
| 109 | + return variableDeclarations.find(decl => decl.id.type === 'Identifier' && decl.id.name === 'load'); |
| 110 | + } |
| 111 | + |
| 112 | + // find `export function load = ...` |
| 113 | + if (exportDecl.declaration && exportDecl.declaration.type === 'FunctionDeclaration') { |
| 114 | + const functionId = exportDecl.declaration.id; |
| 115 | + return functionId?.name === 'load'; |
| 116 | + } |
| 117 | + |
| 118 | + // find `export { load, somethingElse as load, somethingElse as "load" }` |
| 119 | + if (exportDecl.specifiers) { |
| 120 | + return exportDecl.specifiers.find(specifier => { |
| 121 | + return ( |
| 122 | + (specifier.exported.type === 'Identifier' && specifier.exported.name === 'load') || |
| 123 | + (specifier.exported.type === 'StringLiteral' && specifier.exported.value === 'load') |
| 124 | + ); |
| 125 | + }); |
| 126 | + } |
| 127 | + |
| 128 | + return false; |
| 129 | + }); |
| 130 | + |
104 | 131 | if (!hasLoadDeclaration) { |
105 | 132 | // eslint-disable-next-line no-console |
106 | 133 | debug && console.log(`Skipping wrapping ${id} because it doesn't declare a \`load\` function`); |
| 134 | + return false; |
107 | 135 | } |
108 | 136 |
|
109 | | - return !hasSentryContent && hasLoadDeclaration; |
| 137 | + return true; |
110 | 138 | } |
111 | 139 |
|
112 | 140 | /** |
|
0 commit comments