Skip to content

Conversation

0hmX
Copy link

@0hmX 0hmX commented Aug 3, 2025

closes: #123

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.

Minor thing

Copy link
Member

@brunocroh brunocroh left a comment

Choose a reason for hiding this comment

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

You did a great job on that, thank you for your awesome contribution!

I have some comments on a few points, feel free to share your opinion if you don't agree with something.

And just one more thing: could you please check if you ran node --run pre-commit? I think there are some Biome rules that aren't applied.

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.

LGMT ! Thanks for you first contribution.
If you have any feedback about DX on this project let's me know. And if you have any feedback about codemod CLI/platform I'm going to transfer it to them

@AugustinMauroy AugustinMauroy requested a review from a team August 6, 2025 08:32
@AugustinMauroy
Copy link
Member

fro windows failing use https://nodejs.org/api/os.html#oseol instead of \n

@AugustinMauroy
Copy link
Member

we also have few utility you should use it to simplify

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.

Looks like good test cases :)

Regarding cases handled, what about import expressions const { createCredentials } = await import('node:crypto') and variants like const createCredentials = (await import('node:crypto')).then((m) => m.createCredentials)?

I think that is needed in order to say the deprecation is handled.

endPos: statement.range().end.index,
insertedText: `${os.EOL}${newImportStatement}`,
};
localEdits.push(newEdit);
Copy link
Member

@JakobJingleheimer JakobJingleheimer Aug 11, 2025

Choose a reason for hiding this comment

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

nit: why not just write the value of newEdit into push? localEdits.push({…}) newEdits isn't used elsewhere and isn't complicated.

Copy link
Member

Choose a reason for hiding this comment

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

Not necessarily a blocker, but this file has a lot more code than I expected. There are basically 3 things that need handling, 2 of which are mostly the same:

1.1 an import statement
1.2 a require statement
2 createCredentialscreateSecureContext

1.1 & 1.2 the detection is different, but the transformation is the same (the only part changing is mostly irrespective of cjs vs esm). So I would expect something like this pseudo-code:

type findDepExpressions = (ast): {
  node: ASTNode,
  type: 'import-dynamic' | 'import-static' | 'require',
};

const depExpHandlers = {
  require(n: ASTNode) {
    depExpCommonHandler(n);
    // Require-specific bits like namespacing
    return updatedNode;
  },
  'import-dynamic'(n: ASTNode) {
    depExpCommonHandler(n);
    // Dynamic-specific bits like thenable namespacing
    return updatedNode;
  },
  'import-static'(n: ASTNode) {
    depExpCommonHandler(n);
    // Static-specific bits like namespacing
    return updatedNode;
  },
};

for (const dS of findDepExpressions(ast)) edits.push(
  depExpHandlers[ds.type](ds.node),
);

Copy link
Author

Choose a reason for hiding this comment

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

I am open to the idea, but this will cause a significant refactor

Copy link
Member

Choose a reason for hiding this comment

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

Not necessarily a blocker, but this file has a lot more code than I expected. There are basically 3 things that need handling, 2 of which are mostly the same:

Also it's because it's doesn't use any utility.

@0hmX what do you think about using our utility to reduce the amount of code here ?

Copy link
Member

Choose a reason for hiding this comment

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

Niiiice

@AugustinMauroy
Copy link
Member

Looks like good test cases :)

Regarding cases handled, what about import expressions const { createCredentials } = await import('node:crypto') and variants like const createCredentials = (await import('node:crypto')).then((m) => m.createCredentials)?

I think that is needed in order to say the deprecation is handled.

BTW any of our publish codemod support dynamic import

@JakobJingleheimer
Copy link
Member

BTW any of our publish codemod support dynamic import

Sorry, is that a question or a statement? (Do you mean "all of our published codemods support dynamic import"?)

@AugustinMauroy
Copy link
Member

BTW any of our publish codemod support dynamic import

Sorry, is that a question or a statement? (Do you mean "all of our published codemods support dynamic import"?)

It's a fact ! So do we want to support that in general ?

@0hmX
Copy link
Author

0hmX commented Aug 12, 2025

Regarding cases handled, what about import expressions const { createCredentials } = await import('node:crypto') and variants like const createCredentials = (await import('node:crypto')).then((m) => m.createCredentials)?

I did not know we were handling this. I will add a test case for it.

@0hmX 0hmX force-pushed the crypto-createCredentials branch from 24f755d to d057380 Compare August 14, 2025 17:17
@0hmX
Copy link
Author

0hmX commented Aug 14, 2025

Okay, so I ended up rewriting the code, but it's now bigger than the previous version🫠. Yes, I am using the utilities. I added a few more test cases related to pair_pattern and import_specifier.

However, I couldn't get the logic to work for const createCredentials = (await import('node:crypto')).then((m) => m.createCredentials) because the getNodeImportCalls utility does not handle this case. I want to skip it, as adding the extra code would make the file too large.

@JakobJingleheimer
Copy link
Member

Okay, so I ended up rewriting the code, but it's now bigger than the previous version🫠. Yes, I am using the utilities. I added a few more test cases related to pair_pattern and import_specifier.

However, I couldn't get the logic to work for const createCredentials = (await import('node:crypto')).then((m) => m.createCredentials) because the getNodeImportCalls utility does not handle this case. I want to skip it, as adding the extra code would make the file too large.

Thanks! I'm sure it was a fair amount of work 😅 (that's why I said it wasn't necessarily a blocker)

Unfortunately you force-pushed, which wipes the review history. That means the entire PR has to get reviewed again instead of just the pieces recently changed (and that massively increases the effort & time needed to review the latest changes). I've updated the repo settings to now block force-pushing to prevent this happening again (you weren't the only one to do it), but FYI the next review will take me some time to get through now because of that force-push 😬

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.

LGMT !

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.

LGTM :)

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

Comment on lines +69 to +77
if (spec.kind() === 'import_specifier') {
keyNode = spec.field('name');
aliasNode = spec.field('alias');
} else if (spec.kind() === 'pair_pattern') {
keyNode = spec.field('key');
aliasNode = spec.field('value');
} else {
keyNode = spec;
}
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 (spec.kind() === 'import_specifier') {
keyNode = spec.field('name');
aliasNode = spec.field('alias');
} else if (spec.kind() === 'pair_pattern') {
keyNode = spec.field('key');
aliasNode = spec.field('value');
} else {
keyNode = spec;
}
switch (spec.kind() {
case 'import_specifier':
keyNode = spec.field('name');
aliasNode = spec.field('alias');
break;
case 'pair_pattern':
keyNode = spec.field('key');
aliasNode = spec.field('value');
break;
default:
keyNode = spec;
break;
}


for (const spec of relevantSpecifiers) {
let keyNode: SgNode<TypesMap, Kinds<TypesMap>> | null = null;
let aliasNode: SgNode<TypesMap, Kinds<TypesMap>> | null = 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
let aliasNode: SgNode<TypesMap, Kinds<TypesMap>> | null = null;
let aliasNode: SgNode<TypesMap, Kinds<TypesMap>> | null = null;

): Edit[] {
const idNode = statement.child(0);
const declaration = statement.parent();
if (!idNode || !declaration) return [];
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 (!idNode || !declaration) return [];
if (!idNode || !declaration) return [];

Comment on lines +184 to +188
if (idNode.kind() === 'identifier')
return handleNamespaceImport(rootNode, idNode.text(), declaration, 'require');

if (idNode.kind() === 'object_pattern')
return handleDestructuredImport(rootNode, idNode, declaration, 'require');
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 (idNode.kind() === 'identifier')
return handleNamespaceImport(rootNode, idNode.text(), declaration, 'require');
if (idNode.kind() === 'object_pattern')
return handleDestructuredImport(rootNode, idNode, declaration, 'require');
const kind = idNode.kind();
if (kind === 'identifier')
return handleNamespaceImport(rootNode, idNode.text(), declaration, 'require');
if (kind === 'object_pattern')
return handleDestructuredImport(rootNode, idNode, declaration, 'require');

Comment on lines +347 to +352
// @ts-ignore
[getNodeRequireCalls(root, 'crypto'), handleRequire],
// @ts-ignore
[getNodeImportStatements(root, 'crypto'), handleStaticImport],
// @ts-ignore
[getNodeImportCalls(root, 'crypto'), handleDynamicImport],
Copy link
Member

Choose a reason for hiding this comment

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

Why @ts-ignore?

@JakobJingleheimer JakobJingleheimer added the awaiting author Reviewer has requested something from the author label Sep 24, 2025
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: handle crypto.createCredentials() depreciation
5 participants