feat(DEP0121): net._setSimultaneousAccepts()#278
Conversation
AugustinMauroy
left a comment
There was a problem hiding this comment.
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. |
I don't see a question. Is it something we can help with? (Could you point us to it?) |
package.json
Outdated
| "codemod", | ||
| "migrations", | ||
| "node.js" | ||
| "node.js" |
There was a problem hiding this comment.
| "node.js" | |
| "node.js" |
|
What the current state of this pr ? |
The PR is ready to be reviewed. |
AugustinMauroy
left a comment
There was a problem hiding this comment.
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" | |||
There was a problem hiding this comment.
| name: "@nodejs/net-setSimultaneousAccepts-migration" | |
| name: "@nodejs/net-setSimultaneousAccepts-deprecation" |
#namingIsHard @nodejs/userland-migrations what do you think
There was a problem hiding this comment.
Mm, the suggestion is more correct.
| const linesToRemove: Range[] = []; | ||
|
|
||
| const netImportStatements = getAllNetImportStatements(root); | ||
| if (netImportStatements.length === 0) return null; |
There was a problem hiding this comment.
| 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; |
There was a problem hiding this comment.
| 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; |
There was a problem hiding this comment.
Maybe "No changes, nothing to do" for the comment
| ...getNodeImportStatements(root, 'node:net'), | ||
| ...getNodeImportCalls(root, 'node:net'), | ||
| ...getNodeRequireCalls(root, 'node:net'), |
There was a problem hiding this comment.
| ...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; |
There was a problem hiding this comment.
| if (!bindingPath) return; | |
| if (!bindingPath) return; |
| /** | ||
| * Finds all _setSimultaneousAccepts() call expressions | ||
| */ | ||
| function findSetSimultaneousAcceptsCalls( |
There was a problem hiding this comment.
This function isn't valuable. You can "hardcode" this query in the parent functio
| 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); | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
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({ |
JakobJingleheimer
left a comment
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
| "node.js" | |
| "node.js" |
| const net = require("node:net"); | ||
|
|
||
| -net._setSimultaneousAccepts(false); | ||
| const server = net.createServer(); |
There was a problem hiding this comment.
| 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; |
There was a problem hiding this comment.
Maybe "No changes, nothing to do" for the comment
| if (argKind === 'member_expression') { | ||
| handleMemberExpressionArgument(rootNode, argNode, linesToRemove); | ||
| } else if (argKind === 'identifier') { | ||
| handleIdentifierArgument(rootNode, argNode, linesToRemove); | ||
| } |
There was a problem hiding this comment.
nit: switch makes it more clear that it's inspecting the same condition for each.
| 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; | |
| } |
net._setSimultaneousAccepts()
JakobJingleheimer
left a comment
There was a problem hiding this comment.
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.
| /** | ||
| * 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'), | ||
| ]; | ||
| } |
There was a problem hiding this comment.
After this PR was opened, we added this as a built-in utility: @nodejs/codemod-utils:getModuleDependencies
| 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); | ||
| } |
There was a problem hiding this comment.
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.
| 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); | |
| } |
| 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); | |
| } |
| import { | ||
| getNodeImportStatements, | ||
| getNodeImportCalls, | ||
| } from '@nodejs/codemod-utils/ast-grep/import-statement'; | ||
| import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call'; |
There was a problem hiding this comment.
nit (see below)
| 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'; |
| if (argNode) { | ||
| handleCallArgument(rootNode, argNode, linesToRemove); | ||
| } |
There was a problem hiding this comment.
nit:
| if (argNode) { | |
| handleCallArgument(rootNode, argNode, linesToRemove); | |
| } | |
| if (argNode) handleCallArgument(rootNode, argNode, linesToRemove); |
| case 'member_expression': handleMemberExpressionArgument(rootNode, argNode, linesToRemove); break; | ||
| case 'identifier': handleIdentifierArgument(rootNode, argNode, linesToRemove); break; |
There was a problem hiding this comment.
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.
| 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; |
| index: endPos + 1, | ||
| column: range.end.column + 1 | ||
| } |
There was a problem hiding this comment.
nit (formatting/linting)
| index: endPos + 1, | |
| column: range.end.column + 1 | |
| } | |
| column: range.end.column + 1, | |
| index: endPos + 1, | |
| }, |
| if (topLevelStatement) { | ||
| linesToRemove.push(topLevelStatement.range()); | ||
| } |
There was a problem hiding this comment.
nit
| if (topLevelStatement) { | |
| linesToRemove.push(topLevelStatement.range()); | |
| } | |
| if (topLevelStatement) linesToRemove.push(topLevelStatement.range()); |
| 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; | ||
| } |
There was a problem hiding this comment.
I think this can be simplified:
| 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" |
There was a problem hiding this comment.
| "node.js" | |
| "node.js" |
Closes #173