Skip to content

Commit

Permalink
fix(node): Correctly resolve module name
Browse files Browse the repository at this point in the history
  • Loading branch information
timfish committed Dec 31, 2023
1 parent 679e149 commit 8179837
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 45 deletions.
41 changes: 25 additions & 16 deletions packages/node/src/module.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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;
}
56 changes: 27 additions & 29 deletions packages/node/test/module.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});

0 comments on commit 8179837

Please sign in to comment.