Skip to content

feat(DEP0121): net._setSimultaneousAccepts()#278

Open
vespa7 wants to merge 3 commits intonodejs:mainfrom
vespa7:alex/DEP0121
Open

feat(DEP0121): net._setSimultaneousAccepts()#278
vespa7 wants to merge 3 commits intonodejs:mainfrom
vespa7:alex/DEP0121

Conversation

@vespa7
Copy link

@vespa7 vespa7 commented Nov 19, 2025

Closes #173

Copy link
Member

@AugustinMauroy AugustinMauroy left a comment

Choose a reason for hiding this comment

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

Missing test case for dynamic import

@vespa7
Copy link
Author

vespa7 commented Nov 19, 2025

Missing test case for dynamic import

Yes, it’s in draft. It doesn’t need to be corrected yet. I’m waiting for a question to be resolved.

@JakobJingleheimer
Copy link
Member

Yes, it’s in draft. It doesn’t need to be corrected yet. I’m waiting for a question to be resolved.

I don't see a question. Is it something we can help with? (Could you point us to it?)

@vespa7 vespa7 marked this pull request as ready for review November 20, 2025 13:50
@JakobJingleheimer JakobJingleheimer added the awaiting reviewer Author has responded and needs action from the reviewer label Nov 27, 2025
package.json Outdated
"codemod",
"migrations",
"node.js"
"node.js"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"node.js"
"node.js"

@AugustinMauroy
Copy link
Member

What the current state of this pr ?

@vespa7
Copy link
Author

vespa7 commented Nov 28, 2025

What the current state of this pr ?

The PR is ready to be reviewed.

Copy link
Member

@AugustinMauroy AugustinMauroy left a comment

Choose a reason for hiding this comment

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

not too bad, good job but there are serval part of the implementation that need to be discussed

@@ -0,0 +1,21 @@
schema_version: "1.0"
name: "@nodejs/net-setSimultaneousAccepts-migration"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
name: "@nodejs/net-setSimultaneousAccepts-migration"
name: "@nodejs/net-setSimultaneousAccepts-deprecation"

#namingIsHard @nodejs/userland-migrations what do you think

Copy link
Member

Choose a reason for hiding this comment

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

Mm, the suggestion is more correct.

const linesToRemove: Range[] = [];

const netImportStatements = getAllNetImportStatements(root);
if (netImportStatements.length === 0) return null;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (netImportStatements.length === 0) return null;
// If no import found we don't process the file
if (!netImportStatements.length) return null;

processNetImportStatement(rootNode, statement, linesToRemove, edits);
}

if (edits.length === 0 && linesToRemove.length === 0) return null;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (edits.length === 0 && linesToRemove.length === 0) return null;
// If there aren't any change we don't try to modify something
if (!edits.length && !linesToRemove.length) return null;

Copy link
Member

Choose a reason for hiding this comment

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

Maybe "No changes, nothing to do" for the comment

Comment on lines 45 to 47
...getNodeImportStatements(root, 'node:net'),
...getNodeImportCalls(root, 'node:net'),
...getNodeRequireCalls(root, 'node:net'),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
...getNodeImportStatements(root, 'node:net'),
...getNodeImportCalls(root, 'node:net'),
...getNodeRequireCalls(root, 'node:net'),
...getNodeImportStatements(root, 'net'),
...getNodeImportCalls(root, 'net'),
...getNodeRequireCalls(root, 'net'),

the node: isn't needed theses functions catch it

edits: Edit[]
): void {
const bindingPath = resolveBindingPath(statementNode, '$');
if (!bindingPath) return;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (!bindingPath) return;
if (!bindingPath) return;

/**
* Finds all _setSimultaneousAccepts() call expressions
*/
function findSetSimultaneousAcceptsCalls(
Copy link
Member

Choose a reason for hiding this comment

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

This function isn't valuable. You can "hardcode" this query in the parent functio

Comment on lines 154 to 171
for (const objDecl of objDeclarations) {
const objectLiterals = objDecl.findAll({ rule: { kind: 'object' } });

for (const obj of objectLiterals) {
const pairs = obj.findAll({ rule: { kind: 'pair' } });

for (const pair of pairs) {
const key = pair.child(0);
if (key?.text() === propertyName) {
const rangeWithComma = expandRangeToIncludeTrailingComma(
pair.range(),
rootNode.text()
);
linesToRemove.push(rangeWithComma);
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

can we have a loop that push to an array then iterate on this array to avoid 3th level of nested loop

varName: string,
linesToRemove: Range[]
): void {
const varDeclarationStatements = rootNode.findAll({
Copy link
Member

Choose a reason for hiding this comment

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

ditto

Copy link
Member

@JakobJingleheimer JakobJingleheimer left a comment

Choose a reason for hiding this comment

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

Thanks for this! It's a good first :)

I think this could use some additional test-cases that include more things happening from node:net to ensure they don't get broken.

package.json Outdated
"codemod",
"migrations",
"node.js"
"node.js"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"node.js"
"node.js"

Comment on lines 12 to 15
const net = require("node:net");

-net._setSimultaneousAccepts(false);
const server = net.createServer();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const net = require("node:net");
-net._setSimultaneousAccepts(false);
const server = net.createServer();
const net = require("node:net");
- net._setSimultaneousAccepts(false);
const server = net.createServer();

processNetImportStatement(rootNode, statement, linesToRemove, edits);
}

if (edits.length === 0 && linesToRemove.length === 0) return null;
Copy link
Member

Choose a reason for hiding this comment

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

Maybe "No changes, nothing to do" for the comment

Comment on lines 101 to 105
if (argKind === 'member_expression') {
handleMemberExpressionArgument(rootNode, argNode, linesToRemove);
} else if (argKind === 'identifier') {
handleIdentifierArgument(rootNode, argNode, linesToRemove);
}
Copy link
Member

@JakobJingleheimer JakobJingleheimer Dec 1, 2025

Choose a reason for hiding this comment

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

nit: switch makes it more clear that it's inspecting the same condition for each.

Suggested change
if (argKind === 'member_expression') {
handleMemberExpressionArgument(rootNode, argNode, linesToRemove);
} else if (argKind === 'identifier') {
handleIdentifierArgument(rootNode, argNode, linesToRemove);
}
switch(argKind) {
case 'member_expression': handleMemberExpressionArgument(rootNode, argNode, linesToRemove); break;
case 'identifier': handleIdentifierArgument(rootNode, argNode, linesToRemove); break;
}

@JakobJingleheimer JakobJingleheimer added awaiting author Reviewer has requested something from the author and removed awaiting reviewer Author has responded and needs action from the reviewer labels Dec 1, 2025
@JakobJingleheimer JakobJingleheimer changed the title feat(net-setsimultaneousaccepts-migration): create recipe feat(DEP0121): net._setSimultaneousAccepts() Feb 22, 2026
Copy link
Member

@JakobJingleheimer JakobJingleheimer left a comment

Choose a reason for hiding this comment

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

This looks good to me! I see there is some uncertainty (#173 (comment)) about the proper handling for this, so let's get someone from @nodejs/net to chime in before landing.

PS Sorry this took me a while to get back to.

Comment on lines +43 to +52
/**
* Collects all import/require statements for 'node:net'
*/
function getAllNetImportStatements(root: SgRoot<Js>): SgNode<Js>[] {
return [
...getNodeImportStatements(root, 'net'),
...getNodeImportCalls(root, 'net'),
...getNodeRequireCalls(root, 'net'),
];
}
Copy link
Member

Choose a reason for hiding this comment

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

After this PR was opened, we added this as a built-in utility: @nodejs/codemod-utils:getModuleDependencies

Comment on lines +28 to +35
const netImportStatements = getAllNetImportStatements(root);

// If no import found we don't process the file
if (!netImportStatements.length) return null;

for (const statement of netImportStatements) {
processNetImportStatement(rootNode, statement, linesToRemove, edits);
}
Copy link
Member

Choose a reason for hiding this comment

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

The length check is unnecessary: getAllNetImportStatements (and @nodejs/codemod-utils:getModuleDependencies) always return an array, so the for…of won't break and will simply do nothing when the array is empty; then the check right after will handle aborting, affectively achieving the same thing with less code.

Suggested change
const netImportStatements = getAllNetImportStatements(root);
// If no import found we don't process the file
if (!netImportStatements.length) return null;
for (const statement of netImportStatements) {
processNetImportStatement(rootNode, statement, linesToRemove, edits);
}
for (const statement of getAllNetImportStatements(root)) {
processNetImportStatement(rootNode, statement, linesToRemove, edits);
}
Suggested change
const netImportStatements = getAllNetImportStatements(root);
// If no import found we don't process the file
if (!netImportStatements.length) return null;
for (const statement of netImportStatements) {
processNetImportStatement(rootNode, statement, linesToRemove, edits);
}
for (const statement of getModuleDependencies(root)) {
processNetImportStatement(rootNode, statement, linesToRemove, edits);
}

Comment on lines +1 to +5
import {
getNodeImportStatements,
getNodeImportCalls,
} from '@nodejs/codemod-utils/ast-grep/import-statement';
import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call';
Copy link
Member

Choose a reason for hiding this comment

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

nit (see below)

Suggested change
import {
getNodeImportStatements,
getNodeImportCalls,
} from '@nodejs/codemod-utils/ast-grep/import-statement';
import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call';
import { getModuleDependencies } from '@nodejs/codemod-utils/ast-grep/module-dependencies';

Comment on lines +76 to +78
if (argNode) {
handleCallArgument(rootNode, argNode, linesToRemove);
}
Copy link
Member

Choose a reason for hiding this comment

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

nit:

Suggested change
if (argNode) {
handleCallArgument(rootNode, argNode, linesToRemove);
}
if (argNode) handleCallArgument(rootNode, argNode, linesToRemove);

Comment on lines +96 to +97
case 'member_expression': handleMemberExpressionArgument(rootNode, argNode, linesToRemove); break;
case 'identifier': handleIdentifierArgument(rootNode, argNode, linesToRemove); break;
Copy link
Member

Choose a reason for hiding this comment

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

There's some extra indentation on the second case which at first glance makes it look like nested code.

A nit line-break for the break so it doesn't get (visually) lost and look like fall-through.

Suggested change
case 'member_expression': handleMemberExpressionArgument(rootNode, argNode, linesToRemove); break;
case 'identifier': handleIdentifierArgument(rootNode, argNode, linesToRemove); break;
case 'member_expression': handleMemberExpressionArgument(rootNode, argNode, linesToRemove);
break;
case 'identifier': handleIdentifierArgument(rootNode, argNode, linesToRemove);
break;

Comment on lines +180 to +182
index: endPos + 1,
column: range.end.column + 1
}
Copy link
Member

Choose a reason for hiding this comment

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

nit (formatting/linting)

Suggested change
index: endPos + 1,
column: range.end.column + 1
}
column: range.end.column + 1,
index: endPos + 1,
},

Comment on lines +234 to +236
if (topLevelStatement) {
linesToRemove.push(topLevelStatement.range());
}
Copy link
Member

Choose a reason for hiding this comment

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

nit

Suggested change
if (topLevelStatement) {
linesToRemove.push(topLevelStatement.range());
}
if (topLevelStatement) linesToRemove.push(topLevelStatement.range());

Comment on lines +243 to +258
function findTopLevelStatement(node: SgNode<Js>): SgNode<Js> | null {
let current: SgNode<Js> | null = node;

while (current) {
const parent = current.parent();
if (!parent) break;

if (parent.kind() === 'program') {
return current;
}

current = parent;
}

return null;
}
Copy link
Member

Choose a reason for hiding this comment

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

I think this can be simplified:

Suggested change
function findTopLevelStatement(node: SgNode<Js>): SgNode<Js> | null {
let current: SgNode<Js> | null = node;
while (current) {
const parent = current.parent();
if (!parent) break;
if (parent.kind() === 'program') {
return current;
}
current = parent;
}
return null;
}
function findTopLevelStatement(node: SgNode<Js>): SgNode<Js> | null {
let current: SgNode<Js> | null = node;
while (current = current.parent()) {
if (current?.kind() === 'program') return current;
}
return null;
}

I checked with a quick test:

function generateNode(kind) {
	let i = 1;
	return {
		parent() {
			if (i++ < 4) return {
				kind() { return kind },
			};
			return null;
		},
	};
}

findTopLevelStatement(generateNode('not-program'); // null
findTopLevelStatement(generateNode('program'); // { kind: 𝑓 }

"codemod",
"migrations",
"node.js"
"node.js"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"node.js"
"node.js"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting author Reviewer has requested something from the author info needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: handle net._setSimultaneousAccepts() deprecation

6 participants