Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
Empty file.
21 changes: 21 additions & 0 deletions recipes/tls-securepair-to-tlssocket_working/codemod.yaml
Copy link
Member

Choose a reason for hiding this comment

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

there are some copy pasta

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
schema_version: "1.0"
name: "@nodejs/tmpDir-to-tmpdir"
version: "1.0.0"
description: Handle DEP0022 via transforming `tmpDir` to `tmpdir`.
author: nekojanai (Jana)
license: MIT
workflow: workflow.yaml
category: migration

targets:
languages:
- javascript
- typescript

keywords:
- transformation
- migration

registry:
access: public
visibility: public
15 changes: 15 additions & 0 deletions recipes/tls-securepair-to-tlssocket_working/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "@nodejs/tls-securepair-to-tlssocket_working-codemod",
"version": "1.0.1",
"description": "",
"type": "module",
"author": "Maxime Devillet",
"license": "MIT",
"devDependencies": {
"@codemod.com/jssg-types": "^1.0.9"
},
"dependencies": {
"@ast-grep/napi": "^0.40.0",
"@nodejs/codemod-utils": "*"
}
}
132 changes: 132 additions & 0 deletions recipes/tls-securepair-to-tlssocket_working/src/workflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { removeLines } from "@nodejs/codemod-utils/ast-grep/remove-lines";
import type { Edit, SgRoot, Range } from "@codemod.com/jssg-types/main";
import type Js from "@codemod.com/jssg-types/langs/javascript";

function getClosest(node: any, kinds: string[]): any | null {
let current = node.parent();
while (current) {
if (kinds.includes(current.kind())) {
return current;
}
current = current.parent();
}
return null;
}

export default function transform(root: SgRoot<Js>): string | null {
const rootNode = root.root();
const edits: Edit[] = [];
const linesToRemove: Range[] = [];

const importNodes = rootNode.findAll({
rule: {
any: [
{ kind: "import_specifier", has: { kind: "identifier", regex: "^SecurePair$" } },
{ kind: "shorthand_property_identifier_pattern", regex: "^SecurePair$" },
{ kind: "property_identifier", regex: "^SecurePair$" }
]
}
});

for (const node of importNodes) {
if (node.text() === "SecurePair") {
edits.push(node.replace("TLSSocket"));
}
}

const newExpressions = rootNode.findAll({
rule: {
kind: "new_expression",
has: {
any: [
{ kind: "member_expression", has: { field: "property", regex: "^SecurePair$" } },
{ kind: "identifier", regex: "^SecurePair$" }
]
}
}
});

for (const node of newExpressions) {
const callee = node.field("constructor");
if (!callee) continue;

let newConstructorName = "TLSSocket";
if (callee.kind() === "member_expression") {
const object = callee.field("object");
if (object) {
newConstructorName = `${object.text()}.TLSSocket`;
}
}

edits.push(node.replace(`new ${newConstructorName}(socket)`));

const declarator = getClosest(node, ["variable_declarator"]);
if (declarator) {
const idNode = declarator.field("name");
if (idNode) {
const oldName = idNode.text();

let newName = "socket";
if (oldName !== "pair" && oldName !== "SecurePair") {
if (oldName.includes("Pair")) {
newName = oldName.replace("Pair", "Socket");
}
else if (oldName.includes("pair")) {
newName = oldName.replace("pair", "socket");
}
else {
newName = "socket";
}
}

const obsoleteUsages = rootNode.findAll({
rule: {
kind: "member_expression",
all: [
{ has: { field: "object", regex: `^${oldName}$` } },
{ has: { field: "property", regex: "^(cleartext|encrypted)$" } }
]
}
});

for (const usage of obsoleteUsages) {
const statement = getClosest(usage, ["lexical_declaration", "expression_statement"]);
if (statement) {
linesToRemove.push(statement.range());
}
}

edits.push(idNode.replace(newName));

const references = rootNode.findAll({
rule: {
kind: "identifier",
regex: `^${oldName}$`
}
});

for (const ref of references) {
const parent = ref.parent();
if (parent && parent.kind() === 'member_expression') {
const property = parent.field('property');
if (property && property.id() === ref.id()) {
continue;
}
}

if (parent && (parent.kind() === 'import_specifier' || parent.kind() === 'shorthand_property_identifier_pattern')) {
continue;
}

if (ref.id() === idNode.id()) continue;

edits.push(ref.replace(newName));
}
}
}
}

let sourceCode = rootNode.commitEdits(edits);
sourceCode = removeLines(sourceCode, linesToRemove);
return sourceCode;
}
74 changes: 74 additions & 0 deletions recipes/tls-securepair-to-tlssocket_working/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/bash

GREEN='\033[0;32m'
RED='\033[0;31m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
NC='\033[0m'

INPUT_DIR="tests/input"
EXPECTED_DIR="tests/expected"
TEMP_DIR="tests/temp_workzone"

declare -a passed_files
declare -a failed_files

echo -e "${BLUE}${BOLD}=== Starting Codemod Test Suite ===${NC}"

rm -rf "$TEMP_DIR"
mkdir -p "$TEMP_DIR"
cp -r "$INPUT_DIR"/* "$TEMP_DIR"

echo -e "➜ Running codemod on temporary files..."
npx codemod workflow run -w workflow.yaml -t "$TEMP_DIR" > /dev/null 2>&1

echo -e "➜ Verifying results...\n"

for expected_file in "$EXPECTED_DIR"/*; do
filename=$(basename "$expected_file")
generated_file="$TEMP_DIR/$filename"

if [ ! -f "$generated_file" ]; then
echo -e "${RED} [MISSING] $filename${NC}"
failed_files+=("$filename (Missing)")
continue
fi

diff_output=$(diff -u --color=always "$expected_file" "$generated_file")
exit_code=$?

if [ $exit_code -eq 0 ]; then
echo -e " ${GREEN}✔ $filename${NC}"
passed_files+=("$filename")
else
echo -e " ${RED}✘ $filename${NC}"
echo -e "${YELLOW}--- Differences for $filename ---${NC}"
echo "$diff_output"
echo -e "${YELLOW}----------------------------------${NC}\n"
failed_files+=("$filename")
fi
done

rm -rf "$TEMP_DIR"

echo -e "\n${BLUE}${BOLD}=== FINAL REPORT ===${NC}"

if [ ${#passed_files[@]} -gt 0 ]; then
echo -e "\n${GREEN}${BOLD}Passed Tests (${#passed_files[@]}) :${NC}"
for f in "${passed_files[@]}"; do
echo -e " ${GREEN}✔ $f${NC}"
done
fi

if [ ${#failed_files[@]} -gt 0 ]; then
echo -e "\n${RED}${BOLD}Failed Tests (${#failed_files[@]}) :${NC}"
for f in "${failed_files[@]}"; do
echo -e " ${RED}✘ $f${NC}"
done
echo -e "\n${RED}➔ Result: FAILURE${NC}"
exit 1
else
echo -e "\n${GREEN}➔ Result: SUCCESS${NC}"
exit 0
fi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const tls = require('node:tls');

// Using tls.SecurePair constructor
const socket = new tls.TLSSocket(socket);

// Direct import
const { TLSSocket } = require('node:tls');
const socket2 = new TLSSocket(socket);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import tls from 'node:tls';

// Using tls.SecurePair constructor
const socket = new tls.TLSSocket(socket);

// Direct import
import { TLSSocket } from 'node:tls';
const socket2 = new TLSSocket(socket);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const { TLSSocket } = require('node:tls');
const { unrelated } = require('other-module');

const socket = new TLSSocket(socket);

socket.on('error', (err) => {
console.error(err);
});

// Propriétés obsolètes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { TLSSocket } = require('node:tls');

// Nom de variable totalement arbitraire
const socket = new TLSSocket(socket);

// Usage
socket.doSomething();
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import tls from 'node:tls';
import { TLSSocket } from 'node:tls';

// Cas 1 : Via namespace
const socket1 = new tls.TLSSocket(socket);

// Cas 2 : Direct
const socket2 = new TLSSocket(socket);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const tls = require('node:tls');

const socket = new tls.TLSSocket(socket);
const mySocket = new tls.TLSSocket(socket);
const secureSocketInstance = new tls.TLSSocket(socket);

// Nettoyage spécifique à chaque variable
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const tls = require('node:tls');

class ConnectionManager {
constructor() {
if (true) {
const socket = new tls.TLSSocket(socket);
this.init(socket);

if (socket.cleartext) {
console.log("cleaning");
}
}
}
}
10 changes: 10 additions & 0 deletions recipes/tls-securepair-to-tlssocket_working/tests/input/file-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const tls = require('node:tls');

// Using tls.SecurePair constructor
const pair = new tls.SecurePair();
const cleartext = pair.cleartext;
const encrypted = pair.encrypted;

// Direct import
const { SecurePair } = require('node:tls');
const pair2 = new SecurePair();
10 changes: 10 additions & 0 deletions recipes/tls-securepair-to-tlssocket_working/tests/input/file-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import tls from 'node:tls';

// Using tls.SecurePair constructor
const pair = new tls.SecurePair();
const cleartext = pair.cleartext;
const encrypted = pair.encrypted;

// Direct import
import { SecurePair } from 'node:tls';
const pair2 = new SecurePair();
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { SecurePair } = require('node:tls');
const { unrelated } = require('other-module');

const pair = new SecurePair();

pair.on('error', (err) => {
console.error(err);
});

// Propriétés obsolètes
console.log(pair.cleartext);
console.log(pair.encrypted);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const { SecurePair } = require('node:tls');

// Nom de variable totalement arbitraire
const item = new SecurePair();

// Usage
item.doSomething();
item.cleartext.read();
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import tls from 'node:tls';
import { SecurePair } from 'node:tls';

// Cas 1 : Via namespace
const pair1 = new tls.SecurePair();
const t1 = pair1.cleartext;

// Cas 2 : Direct
const pair2 = new SecurePair();
const t2 = pair2.encrypted;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const tls = require('node:tls');

const pair = new tls.SecurePair();
const myPair = new tls.SecurePair();
const securePairInstance = new tls.SecurePair();

// Nettoyage spécifique à chaque variable
pair.cleartext.write('hello');
myPair.encrypted.write('world');
Loading