-
-
Notifications
You must be signed in to change notification settings - Fork 29
feat(net-setsimultaneousaccepts-migration): create recipe #278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
package.json
Outdated
| "migrations", | ||
| "node.js" | ||
| ], | ||
| "node.js" ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should revert this change
AugustinMauroy
left a comment
There was a problem hiding this 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
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?) |
| "codemod", | ||
| "migrations", | ||
| "node.js" | ||
| "node.js" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| "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.
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" | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| name: "@nodejs/net-setSimultaneousAccepts-migration" | |
| name: "@nodejs/net-setSimultaneousAccepts-deprecation" |
#namingIsHard @nodejs/userland-migrations what do you think
| const linesToRemove: Range[] = []; | ||
|
|
||
| const netImportStatements = getAllNetImportStatements(root); | ||
| if (netImportStatements.length === 0) return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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.
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
| ...getNodeImportStatements(root, 'node:net'), | ||
| ...getNodeImportCalls(root, 'node:net'), | ||
| ...getNodeRequireCalls(root, 'node:net'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ...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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (!bindingPath) return; | |
| if (!bindingPath) return; |
| /** | ||
| * Finds all _setSimultaneousAccepts() call expressions | ||
| */ | ||
| function findSetSimultaneousAcceptsCalls( |
There was a problem hiding this comment.
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
| const objDeclarations = rootNode.findAll({ | ||
| rule: { | ||
| any: [ | ||
| { pattern: `const ${objectName} = $_` }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why ast kind/ast query can we have something stronger ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm, I think there's probably a built-in way from ast-grep to get this without needing such a wide pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand the scenario correctly, it can be rewritten as something like the code below.
It finds all variable declarations that use the name objectName.
const objDeclarations = rootNode.findAll({
kind: 'variable_declarator',
has: {
kind: 'identifier',
field: 'name',
patern: objctName,
}
})There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking in something like this:
const pair = root
.root()
.findAll({ rule: { kind: "variable_declarator" } })
.filter((decl) => decl.field("name")?.text() === objectName)
.flatMap((decl) => decl.findAll({ rule: { kind: "pair" } }))
.filter((p) => p.field("key")?.text() === keyName)
.map((pair) => pair.field("value")?.text())[0]There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WTF that completely crazy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brunocroh yeah, that's exactly the sort of thing I was thinking :)
@vespa7 that is a bit… verbose, and I suspect, overly manual (it looks a bit like a Rube Goldberg machine as code 😄). I think there is a more concise way to do it. I would try something like Bruno suggested.
@AugustinMauroy that's maybe not the most constructive way to phrase it 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops sorry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're misunderstanding what @vespa7's comment is saying due to the thread, but the equivalent to @brunocroh's code in Alex's code is
const pair = rootNode
.findAll({ rule: { kind: "variable_declarator" } })
.filter((decl) => decl.field("name")?.text() === objectName)
If Brunos' code works it might be a bit better for that chunk, but the complete piece is substituting
const objDeclarations = rootNode.findAll({
rule: {
any: [
{ pattern: `const ${objectName} = $_` },
{ pattern: `let ${objectName} = $_` },
{ pattern: `var ${objectName} = $_` },
],
},
});
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);
}
}
}
}
And if you got that correctly I'm not sure how the new piece looks more verbose. Following on Bruno's proposal for the whole snippet, maybe something like
const pairs = rootNode
.findAll({
rule: {
kind: "variable_declarator",
has: {
kind: "identifier",
field: "name",
pattern: objectName,
},
},
})
.flatMap((decl) =>
decl.findAll({
rule: {
kind: "pair",
has: {
field: "key",
regex: keyName,
},
},
}),
);
You can break it in the middle to give explanatory names to the steps
| 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.
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({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
JakobJingleheimer
left a comment
There was a problem hiding this 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.
| "codemod", | ||
| "migrations", | ||
| "node.js" | ||
| "node.js" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| "node.js" | |
| "node.js" |
| const net = require("node:net"); | ||
|
|
||
| -net._setSimultaneousAccepts(false); | ||
| const server = net.createServer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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.
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
| if (argKind === 'member_expression') { | ||
| handleMemberExpressionArgument(rootNode, argNode, linesToRemove); | ||
| } else if (argKind === 'identifier') { | ||
| handleIdentifierArgument(rootNode, argNode, linesToRemove); | ||
| } |
There was a problem hiding this comment.
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.
| 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; | |
| } |
| rule: { pattern: `${objectName}.${propertyName}` }, | ||
| }); | ||
|
|
||
| // Only remove if this is the only reference |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the extra "only" is kind of cumbersome to read
| // Only remove if this is the only reference | |
| // Remove when this is the only reference |
| const objDeclarations = rootNode.findAll({ | ||
| rule: { | ||
| any: [ | ||
| { pattern: `const ${objectName} = $_` }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm, I think there's probably a built-in way from ast-grep to get this without needing such a wide pattern.
Closes #173