diff --git a/packages/node/src/module.ts b/packages/node/src/module.ts index 6085813e6035..73364493ddb2 100644 --- a/packages/node/src/module.ts +++ b/packages/node/src/module.ts @@ -1,6 +1,5 @@ import { posix, sep } from 'path'; - -const isWindowsPlatform = sep === '\\'; +import { dirname } from '@sentry/utils'; /** normalizes Windows paths */ function normalizeWindowsPath(path: string): string { @@ -9,52 +8,62 @@ function normalizeWindowsPath(path: string): string { .replace(/\\/g, '/'); // replace all `\` instances with `/` } +// We cache this so we don't have to recompute it +let basePath: string | undefined; + +function getBasePath(): string { + if (!basePath) { + const baseDir = + require && require.main && require.main.filename ? dirname(require.main.filename) : global.process.cwd(); + basePath = `${baseDir}/`; + } + + return basePath; +} + /** Gets the module from a filename */ export function getModuleFromFilename( filename: string | undefined, - normalizeWindowsPathSeparator: boolean = isWindowsPlatform, + basePath: string = getBasePath(), + isWindows: boolean = sep === '\\', ): string | undefined { if (!filename) { return; } - const normalizedFilename = normalizeWindowsPathSeparator ? normalizeWindowsPath(filename) : filename; + const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath; + const normalizedFilename = isWindows ? normalizeWindowsPath(filename) : filename; // eslint-disable-next-line prefer-const - let { root, dir, base: basename, ext } = posix.parse(normalizedFilename); - - const base = (require && require.main && require.main.filename && dir) || global.process.cwd(); - - const normalizedBase = `${base}/`; - - // It's specifically a module - let file = basename; + let { dir, base: file, ext } = posix.parse(normalizedFilename); if (ext === '.js' || ext === '.mjs' || ext === '.cjs') { file = file.slice(0, ext.length * -1); } - if (!root && !dir) { + if (!dir) { // No dirname whatsoever dir = '.'; } - let n = dir.lastIndexOf('/node_modules/'); + let n = dir.lastIndexOf('/node_modules'); if (n > -1) { - // /node_modules/ is 14 chars return `${dir.slice(n + 14).replace(/\//g, '.')}:${file}`; } + // Let's see if it's a part of the main module // To be a part of main module, it has to share the same base n = `${dir}/`.lastIndexOf(normalizedBase, 0); - if (n === 0) { let moduleName = dir.slice(normalizedBase.length).replace(/\//g, '.'); + if (moduleName) { moduleName += ':'; } moduleName += file; + return moduleName; } + return file; } diff --git a/packages/node/test/module.test.ts b/packages/node/test/module.test.ts index 89c8878a433e..04a6a95a7888 100644 --- a/packages/node/test/module.test.ts +++ b/packages/node/test/module.test.ts @@ -1,42 +1,40 @@ import { getModuleFromFilename } from '../src/module'; -function withFilename(fn: () => void, filename: string) { - const prevFilename = require.main?.filename; - if (require.main?.filename) { - require.main.filename = filename; - } - - try { - fn(); - } finally { - if (require.main && prevFilename) { - require.main.filename = prevFilename; - } - } -} - describe('getModuleFromFilename', () => { test('Windows', () => { - withFilename(() => { - expect(getModuleFromFilename('C:\\Users\\users\\Tim\\Desktop\\node_modules\\module.js', true)).toEqual('module'); - }, 'C:\\Users\\Tim\\app.js'); + expect( + getModuleFromFilename('C:\\Users\\Tim\\node_modules\\some-dep\\module.js', 'C:\\Users\\Tim\\', true), + ).toEqual('some-dep:module'); + + expect(getModuleFromFilename('C:\\Users\\Tim\\some\\more\\feature.js', 'C:\\Users\\Tim\\', true)).toEqual( + 'some.more:feature', + ); }); test('POSIX', () => { - withFilename(() => { - expect(getModuleFromFilename('/Users/users/Tim/Desktop/node_modules/module.js')).toEqual('module'); - }, '/Users/Tim/app.js'); + expect(getModuleFromFilename('/Users/Tim/node_modules/some-dep/module.js', '/Users/Tim/')).toEqual( + 'some-dep:module', + ); + + expect(getModuleFromFilename('/Users/Tim/some/more/feature.js', '/Users/Tim/')).toEqual('some.more:feature'); + expect(getModuleFromFilename('/Users/Tim/main.js', '/Users/Tim/')).toEqual('main'); + }); + + test('.mjs', () => { + expect(getModuleFromFilename('/Users/Tim/node_modules/some-dep/module.mjs', '/Users/Tim/')).toEqual( + 'some-dep:module', + ); }); - test('POSIX .mjs', () => { - withFilename(() => { - expect(getModuleFromFilename('/Users/users/Tim/Desktop/node_modules/module.mjs')).toEqual('module'); - }, '/Users/Tim/app.js'); + test('.cjs', () => { + expect(getModuleFromFilename('/Users/Tim/node_modules/some-dep/module.cjs', '/Users/Tim/')).toEqual( + 'some-dep:module', + ); }); - test('POSIX .cjs', () => { - withFilename(() => { - expect(getModuleFromFilename('/Users/users/Tim/Desktop/node_modules/module.cjs')).toEqual('module'); - }, '/Users/Tim/app.js'); + test('node internal', () => { + expect(getModuleFromFilename('node.js', '/Users/Tim/')).toEqual('node'); + expect(getModuleFromFilename('node:internal/process/task_queues', '/Users/Tim/')).toEqual('task_queues'); + expect(getModuleFromFilename('node:internal/timers', '/Users/Tim/')).toEqual('timers'); }); });