Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions benchmark/internal/util_isinsidenodemodules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use strict';
const common = require('../common.js');
const assert = require('assert');

const bench = common.createBenchmark(main, {
n: [1e6],
stackCount: [99, 101],
method: ['isInsideNodeModules', 'noop'],
}, {
flags: ['--expose-internals', '--disable-warning=internal/test/binding'],
});

function main({ n, stackCount, method }) {
const { internalBinding } = require('internal/test/binding');
const { isInsideNodeModules } = internalBinding('util');

const testFunction = method === 'noop' ?
() => {
bench.start();
for (let i = 0; i < n; i++) {
noop();
}
bench.end(n);
} :
() => {
Error.stackTraceLimit = Infinity;
const existingStackFrameCount = new Error().stack.split('\n').length - 1;
assert.strictEqual(existingStackFrameCount, stackCount);

bench.start();
for (let i = 0; i < n; i++) {
isInsideNodeModules();
}
bench.end(n);
};

// Excluding the message line.
const existingStackFrameCount = new Error().stack.split('\n').length - 1;
// Excluding the test function itself.
nestCallStack(stackCount - existingStackFrameCount - 1, testFunction);
}

function nestCallStack(depth, callback) {
// nestCallStack(1) already adds a stack frame, so we stop at 1.
if (depth === 1) {
return callback();
}
return nestCallStack(depth - 1, callback);
}

function noop() {}
5 changes: 2 additions & 3 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,14 @@ function showFlaggedDeprecation() {
if (bufferWarningAlreadyEmitted ||
++nodeModulesCheckCounter > 10000 ||
(!require('internal/options').getOptionValue('--pending-deprecation') &&
isInsideNodeModules(100, true))) {
isInsideNodeModules(3))) {
// We don't emit a warning, because we either:
// - Already did so, or
// - Already checked too many times whether a call is coming
// from node_modules and want to stop slowing down things, or
// - We aren't running with `--pending-deprecation` enabled,
// and the code is inside `node_modules`.
// - We found node_modules in up to the topmost 100 frames, or
// there are more than 100 frames and we don't want to search anymore.
// - If the topmost non-internal frame is not inside `node_modules`.
return;
}

Expand Down
5 changes: 2 additions & 3 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -1537,9 +1537,8 @@ function loadESMFromCJS(mod, filename, format, source) {
} else if (mod[kIsCachedByESMLoader]) {
// It comes from the require() built for `import cjs` and doesn't have a parent recorded
// in the CJS module instance. Inspect the stack trace to see if the require()
// comes from node_modules and reduce the noise. If there are more than 100 frames,
// just give up and assume it is under node_modules.
shouldEmitWarning = !isInsideNodeModules(100, true);
// comes from node_modules as a direct call and reduce the noise.
shouldEmitWarning = !isInsideNodeModules();
}
} else {
shouldEmitWarning = true;
Expand Down
2 changes: 1 addition & 1 deletion lib/punycode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const {
isInsideNodeModules,
} = internalBinding('util');

if (!isInsideNodeModules(100, true)) {
if (!isInsideNodeModules()) {
process.emitWarning(
'The `punycode` module is deprecated. Please use a userland ' +
'alternative instead.',
Expand Down
2 changes: 1 addition & 1 deletion lib/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ const {
let urlParseWarned = false;

function urlParse(url, parseQueryString, slashesDenoteHost) {
if (!urlParseWarned && !isInsideNodeModules(100, true)) {
if (!urlParseWarned && !isInsideNodeModules(2)) {
urlParseWarned = true;
process.emitWarning(
'`url.parse()` behavior is not standardized and prone to ' +
Expand Down
30 changes: 13 additions & 17 deletions src/node_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -320,23 +320,21 @@ static void GetCallSites(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(callsites);
}

/**
* Checks whether the current call directly initiated from a file inside
* node_modules. This checks up to `frame_limit` stack frames, until it finds
* a frame that is not part of node internal modules.
*/
static void IsInsideNodeModules(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
CHECK_EQ(args.Length(), 2);
CHECK(args[0]->IsInt32()); // frame_limit
// The second argument is the default value.

int frames_limit = args[0].As<v8::Int32>()->Value();
int frames_limit = (args.Length() > 0 && args[0]->IsInt32())
? args[0].As<v8::Int32>()->Value()
: 10;
Local<StackTrace> stack =
StackTrace::CurrentStackTrace(isolate, frames_limit);
int frame_count = stack->GetFrameCount();

// If the search requires looking into more than |frames_limit| frames, give
// up and return the specified default value.
if (frame_count == frames_limit) {
return args.GetReturnValue().Set(args[1]);
}

bool result = false;
for (int i = 0; i < frame_count; ++i) {
Local<StackFrame> stack_frame = stack->GetFrame(isolate, i);
Expand All @@ -350,13 +348,11 @@ static void IsInsideNodeModules(const FunctionCallbackInfo<Value>& args) {
if (script_name_str.starts_with("node:")) {
continue;
}
if (script_name_str.find("/node_modules/") != std::string::npos ||
script_name_str.find("\\node_modules\\") != std::string::npos ||
script_name_str.find("/node_modules\\") != std::string::npos ||
script_name_str.find("\\node_modules/") != std::string::npos) {
result = true;
break;
}
result = script_name_str.find("/node_modules/") != std::string::npos ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just use std::string::contains here I believe

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's C++23 for the string classes.

script_name_str.find("\\node_modules\\") != std::string::npos ||
script_name_str.find("/node_modules\\") != std::string::npos ||
script_name_str.find("\\node_modules/") != std::string::npos;
break;
}

args.GetReturnValue().Set(result);
Expand Down
36 changes: 36 additions & 0 deletions test/parallel/test-internal-util-isinsidenodemodules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

// Flags: --expose-internals

const common = require('../common');
const assert = require('assert');
const vm = require('vm');

const { internalBinding } = require('internal/test/binding');
const { isInsideNodeModules } = internalBinding('util');

const script = new vm.Script(`
const runInsideNodeModules = (cb) => {
return cb();
};

runInsideNodeModules;
`, {
filename: '/workspace/node_modules/test.js',
});
const runInsideNodeModules = script.runInThisContext();

// Test when called directly inside node_modules
assert.strictEqual(runInsideNodeModules(isInsideNodeModules), true);

// Test when called inside a user callback from node_modules
runInsideNodeModules(common.mustCall(() => {
function nonNodeModulesFunction() {
assert.strictEqual(isInsideNodeModules(), false);
}

nonNodeModulesFunction();
}));

// Test when called outside node_modules
assert.strictEqual(isInsideNodeModules(), false);
2 changes: 1 addition & 1 deletion typings/internalBinding/util.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export interface UtilBinding {
guessHandleType(fd: number): 'TCP' | 'TTY' | 'UDP' | 'FILE' | 'PIPE' | 'UNKNOWN';
parseEnv(content: string): Record<string, string>;
styleText(format: Array<string> | string, text: string): string;
isInsideNodeModules(frameLimit: number, defaultValue: unknown): boolean;
isInsideNodeModules(frameLimit?: number): boolean;
constructSharedArrayBuffer(length?: number): SharedArrayBuffer;

constants: {
Expand Down
Loading