From 8551f9a2b5ec65b3b01082e5125ff9c172cbf221 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Fri, 26 Dec 2025 20:58:34 -0500 Subject: [PATCH 1/4] feat(route-del-to-delete): add migration codemod for app.del() to app.delete() --- codemods/route-del-to-delete/README.md | 21 ++++++++++ codemods/route-del-to-delete/codemod.yaml | 24 +++++++++++ codemods/route-del-to-delete/package.json | 22 ++++++++++ codemods/route-del-to-delete/src/workflow.ts | 40 +++++++++++++++++++ .../tests/expected/delete.ts | 39 ++++++++++++++++++ .../route-del-to-delete/tests/input/delete.ts | 39 ++++++++++++++++++ codemods/route-del-to-delete/workflow.yaml | 28 +++++++++++++ 7 files changed, 213 insertions(+) create mode 100644 codemods/route-del-to-delete/README.md create mode 100644 codemods/route-del-to-delete/codemod.yaml create mode 100644 codemods/route-del-to-delete/package.json create mode 100644 codemods/route-del-to-delete/src/workflow.ts create mode 100644 codemods/route-del-to-delete/tests/expected/delete.ts create mode 100644 codemods/route-del-to-delete/tests/input/delete.ts create mode 100644 codemods/route-del-to-delete/workflow.yaml diff --git a/codemods/route-del-to-delete/README.md b/codemods/route-del-to-delete/README.md new file mode 100644 index 0000000..7334a42 --- /dev/null +++ b/codemods/route-del-to-delete/README.md @@ -0,0 +1,21 @@ +# Migrate legacy `app.del()` to `app.delete()` + +Migrates usage of the legacy APIs `app.del()` to `app.delete()`. +Initially, `del` was used instead of `delete`, because `delete` is a reserved keyword in JavaScript. However, as of ECMAScript 6, `delete` and other reserved keywords can legally be used as property names. + +## Example + +### Migrating `app.del()` + +The migration involves replacing instances of `app.del()` with `app.delete()`. + +```diff +- app.del('/some-route', (req, res) => { ++ app.delete('/some-route', (req, res) => { + // Some logic here + }); +``` + +## References + +- [Migration of app.del()](https://expressjs.com/en/guide/migrating-5.html#app.del) diff --git a/codemods/route-del-to-delete/codemod.yaml b/codemods/route-del-to-delete/codemod.yaml new file mode 100644 index 0000000..d70f094 --- /dev/null +++ b/codemods/route-del-to-delete/codemod.yaml @@ -0,0 +1,24 @@ +schema_version: "1.0" +name: "@expressjs/route-del-to-delete" +version: "1.0.0" +description: Migrates usage of the legacy APIs `app.del()` to `app.delete()` +author: bjohansebas (Sebastian Beltran) +license: MIT +workflow: workflow.yaml +category: migration + +targets: + languages: + - javascript + - typescript + +keywords: + - transformation + - migration + - express + - redirect + - location + +registry: + access: public + visibility: public \ No newline at end of file diff --git a/codemods/route-del-to-delete/package.json b/codemods/route-del-to-delete/package.json new file mode 100644 index 0000000..5482aed --- /dev/null +++ b/codemods/route-del-to-delete/package.json @@ -0,0 +1,22 @@ +{ + "name": "@expressjs/route-del-to-delete", + "private": true, + "version": "1.0.0", + "description": "Migrates usage of the legacy APIs `app.del` to `app.delete`.", + "type": "module", + "scripts": { + "test": "npx codemod jssg test -l typescript ./src/workflow.ts ./" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/expressjs/codemod.git", + "directory": "codemods/route-del-to-delete", + "bugs": "https://github.com/expressjs/codemod/issues" + }, + "author": "bjohansebas (Sebastian Beltran)", + "license": "MIT", + "homepage": "https://github.com/expressjs/codemod/blob/main/codemods/route-del-to-delete/README.md", + "devDependencies": { + "@codemod.com/jssg-types": "^1.3.1" + } +} diff --git a/codemods/route-del-to-delete/src/workflow.ts b/codemods/route-del-to-delete/src/workflow.ts new file mode 100644 index 0000000..adae51a --- /dev/null +++ b/codemods/route-del-to-delete/src/workflow.ts @@ -0,0 +1,40 @@ +import type Js from '@codemod.com/jssg-types/src/langs/javascript' +import type { Edit, SgRoot } from '@codemod.com/jssg-types/src/main' + +async function transform(root: SgRoot): Promise { + const rootNode = root.root() + + const nodes = rootNode.findAll({ + rule: { + pattern: '$OBJ.$METHOD($$$ARG)', + }, + constraints: { + METHOD: { regex: '^(del)$' }, + }, + }) + + const edits: Edit[] = [] + + for (const call of nodes) { + const method = call.getMatch('METHOD') + const args = call.getMultipleMatches('ARG') + if (!method) continue + + // $$$ARG yields argument nodes interleaved with separators, so arg nodes are at 0,2,4... + const first = args[0] + if (!first) continue + + const isString = first.is('string') + const isRegexp = first.is('regexp') || first.is('regex') || first.is('regular_expression') + const isArray = first.is('array') || first.is('array_expression') + + if (!isString && !isRegexp && !isArray) continue + + edits.push(method.replace('delete')) + } + + if (edits.length === 0) return null + return rootNode.commitEdits(edits) +} + +export default transform diff --git a/codemods/route-del-to-delete/tests/expected/delete.ts b/codemods/route-del-to-delete/tests/expected/delete.ts new file mode 100644 index 0000000..b1dbf42 --- /dev/null +++ b/codemods/route-del-to-delete/tests/expected/delete.ts @@ -0,0 +1,39 @@ +import express from "express"; + +const app = express(); + +app.get("/", (req, res) => {}); + +app.delete([""],() => { + myImportantLogic(); +}); + +app.delete([],() => { + myImportantLogic(); +}); + +app.delete(/d/,() => { + myImportantLogic(); +}); + +app.del(() => { + myImportantLogic(); +}); + +app.del(function () { + myImportantLogic(); +}); + +app.delete("/old", () => { + myImportantLogic(); +}); + +function noModify() { + let a + + app.del(a) +} + +const myImportantLogic = () => { + console.log("making sure it's there"); +}; diff --git a/codemods/route-del-to-delete/tests/input/delete.ts b/codemods/route-del-to-delete/tests/input/delete.ts new file mode 100644 index 0000000..aeab3e3 --- /dev/null +++ b/codemods/route-del-to-delete/tests/input/delete.ts @@ -0,0 +1,39 @@ +import express from "express"; + +const app = express(); + +app.get("/", (req, res) => {}); + +app.del([""],() => { + myImportantLogic(); +}); + +app.del([],() => { + myImportantLogic(); +}); + +app.del(/d/,() => { + myImportantLogic(); +}); + +app.del(() => { + myImportantLogic(); +}); + +app.del(function () { + myImportantLogic(); +}); + +app.del("/old", () => { + myImportantLogic(); +}); + +function noModify() { + let a + + app.del(a) +} + +const myImportantLogic = () => { + console.log("making sure it's there"); +}; diff --git a/codemods/route-del-to-delete/workflow.yaml b/codemods/route-del-to-delete/workflow.yaml new file mode 100644 index 0000000..0253be9 --- /dev/null +++ b/codemods/route-del-to-delete/workflow.yaml @@ -0,0 +1,28 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/codemod-com/codemod/refs/heads/main/schemas/workflow.json + +version: "1" + +nodes: + - id: apply-transforms + name: Apply AST Transformations + type: automatic + runtime: + type: direct + steps: + - name: Migrates usage of the legacy APIs `app.del()` to `app.delete()` + js-ast-grep: + js_file: src/workflow.ts + base_path: . + semantic_analysis: file + include: + - "**/*.cjs" + - "**/*.js" + - "**/*.jsx" + - "**/*.mjs" + - "**/*.cts" + - "**/*.mts" + - "**/*.ts" + - "**/*.tsx" + exclude: + - "**/node_modules/**" + language: typescript \ No newline at end of file From 1c2c93feea653a234865ea19b9e880d748631363 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Fri, 9 Jan 2026 18:05:14 -0500 Subject: [PATCH 2/4] fix(workflow): simplify early return checks for nodes and edits --- codemods/route-del-to-delete/src/workflow.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/codemods/route-del-to-delete/src/workflow.ts b/codemods/route-del-to-delete/src/workflow.ts index adae51a..6d74a97 100644 --- a/codemods/route-del-to-delete/src/workflow.ts +++ b/codemods/route-del-to-delete/src/workflow.ts @@ -13,6 +13,8 @@ async function transform(root: SgRoot): Promise { }, }) + if (!nodes.length) return null + const edits: Edit[] = [] for (const call of nodes) { @@ -33,7 +35,8 @@ async function transform(root: SgRoot): Promise { edits.push(method.replace('delete')) } - if (edits.length === 0) return null + if (!edits.length) return null + return rootNode.commitEdits(edits) } From e8a31f5c6d954ce904d79a7111044758b5d2e282 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Fri, 9 Jan 2026 18:05:27 -0500 Subject: [PATCH 3/4] fix(codemod): update repository URL in codemod.yaml --- codemods/route-del-to-delete/codemod.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/codemods/route-del-to-delete/codemod.yaml b/codemods/route-del-to-delete/codemod.yaml index d70f094..cece85c 100644 --- a/codemods/route-del-to-delete/codemod.yaml +++ b/codemods/route-del-to-delete/codemod.yaml @@ -5,6 +5,7 @@ description: Migrates usage of the legacy APIs `app.del()` to `app.delete()` author: bjohansebas (Sebastian Beltran) license: MIT workflow: workflow.yaml +repository: "https://github.com/expressjs/codemod/tree/HEAD/codemods/route-del-to-delete" category: migration targets: From 2afc6ccf1ee891880246fbe462e81f4101bdc357 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Tue, 13 Jan 2026 09:58:16 -0500 Subject: [PATCH 4/4] fix(docs): clarify deprecation of app.del() in migration guide --- codemods/route-del-to-delete/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codemods/route-del-to-delete/README.md b/codemods/route-del-to-delete/README.md index 7334a42..250e5c6 100644 --- a/codemods/route-del-to-delete/README.md +++ b/codemods/route-del-to-delete/README.md @@ -1,7 +1,7 @@ # Migrate legacy `app.del()` to `app.delete()` Migrates usage of the legacy APIs `app.del()` to `app.delete()`. -Initially, `del` was used instead of `delete`, because `delete` is a reserved keyword in JavaScript. However, as of ECMAScript 6, `delete` and other reserved keywords can legally be used as property names. +Initially, `del` was used instead of `delete`, because `delete` is a reserved keyword in JavaScript. However, as of ECMAScript 6, `delete` and other reserved keywords can legally be used as property names. The `app.del()` method was deprecated in Express 4 and removed in Express 5. ## Example