Skip to content

Commit ce5c9ad

Browse files
authored
feat(route-del-to-delete): add migration codemod for app.del() to app.delete() (#102)
* feat(route-del-to-delete): add migration codemod for app.del() to app.delete() * fix(workflow): simplify early return checks for nodes and edits * fix(codemod): update repository URL in codemod.yaml * fix(docs): clarify deprecation of app.del() in migration guide
1 parent d9782a6 commit ce5c9ad

8 files changed

Lines changed: 229 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Migrate legacy `app.del()` to `app.delete()`
2+
3+
Migrates usage of the legacy APIs `app.del()` to `app.delete()`.
4+
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.
5+
6+
## Example
7+
8+
### Migrating `app.del()`
9+
10+
The migration involves replacing instances of `app.del()` with `app.delete()`.
11+
12+
```diff
13+
- app.del('/some-route', (req, res) => {
14+
+ app.delete('/some-route', (req, res) => {
15+
// Some logic here
16+
});
17+
```
18+
19+
## References
20+
21+
- [Migration of app.del()](https://expressjs.com/en/guide/migrating-5.html#app.del)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
schema_version: "1.0"
2+
name: "@expressjs/route-del-to-delete"
3+
version: "1.0.0"
4+
description: Migrates usage of the legacy APIs `app.del()` to `app.delete()`
5+
author: bjohansebas (Sebastian Beltran)
6+
license: MIT
7+
workflow: workflow.yaml
8+
repository: "https://github.com/expressjs/codemod/tree/HEAD/codemods/route-del-to-delete"
9+
category: migration
10+
11+
targets:
12+
languages:
13+
- javascript
14+
- typescript
15+
16+
keywords:
17+
- transformation
18+
- migration
19+
- express
20+
- redirect
21+
- location
22+
23+
registry:
24+
access: public
25+
visibility: public
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "@expressjs/route-del-to-delete",
3+
"private": true,
4+
"version": "1.0.0",
5+
"description": "Migrates usage of the legacy APIs `app.del` to `app.delete`.",
6+
"type": "module",
7+
"scripts": {
8+
"test": "npx codemod jssg test -l typescript ./src/workflow.ts ./"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/expressjs/codemod.git",
13+
"directory": "codemods/route-del-to-delete",
14+
"bugs": "https://github.com/expressjs/codemod/issues"
15+
},
16+
"author": "bjohansebas (Sebastian Beltran)",
17+
"license": "MIT",
18+
"homepage": "https://github.com/expressjs/codemod/blob/main/codemods/route-del-to-delete/README.md",
19+
"devDependencies": {
20+
"@codemod.com/jssg-types": "^1.3.1"
21+
}
22+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import type Js from '@codemod.com/jssg-types/src/langs/javascript'
2+
import type { Edit, SgRoot } from '@codemod.com/jssg-types/src/main'
3+
4+
async function transform(root: SgRoot<Js>): Promise<string | null> {
5+
const rootNode = root.root()
6+
7+
const nodes = rootNode.findAll({
8+
rule: {
9+
pattern: '$OBJ.$METHOD($$$ARG)',
10+
},
11+
constraints: {
12+
METHOD: { regex: '^(del)$' },
13+
},
14+
})
15+
16+
if (!nodes.length) return null
17+
18+
const edits: Edit[] = []
19+
20+
for (const call of nodes) {
21+
const method = call.getMatch('METHOD')
22+
const args = call.getMultipleMatches('ARG')
23+
if (!method) continue
24+
25+
// $$$ARG yields argument nodes interleaved with separators, so arg nodes are at 0,2,4...
26+
const first = args[0]
27+
if (!first) continue
28+
29+
const isString = first.is('string')
30+
const isRegexp = first.is('regexp') || first.is('regex') || first.is('regular_expression')
31+
const isArray = first.is('array') || first.is('array_expression')
32+
33+
if (!isString && !isRegexp && !isArray) continue
34+
35+
edits.push(method.replace('delete'))
36+
}
37+
38+
if (!edits.length) return null
39+
40+
return rootNode.commitEdits(edits)
41+
}
42+
43+
export default transform
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import express from "express";
2+
3+
const app = express();
4+
5+
app.get("/", (req, res) => {});
6+
7+
app.delete([""],() => {
8+
myImportantLogic();
9+
});
10+
11+
app.delete([],() => {
12+
myImportantLogic();
13+
});
14+
15+
app.delete(/d/,() => {
16+
myImportantLogic();
17+
});
18+
19+
app.del(() => {
20+
myImportantLogic();
21+
});
22+
23+
app.del(function () {
24+
myImportantLogic();
25+
});
26+
27+
app.delete("/old", () => {
28+
myImportantLogic();
29+
});
30+
31+
function noModify() {
32+
let a
33+
34+
app.del(a)
35+
}
36+
37+
const myImportantLogic = () => {
38+
console.log("making sure it's there");
39+
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import express from "express";
2+
3+
const app = express();
4+
5+
app.get("/", (req, res) => {});
6+
7+
app.del([""],() => {
8+
myImportantLogic();
9+
});
10+
11+
app.del([],() => {
12+
myImportantLogic();
13+
});
14+
15+
app.del(/d/,() => {
16+
myImportantLogic();
17+
});
18+
19+
app.del(() => {
20+
myImportantLogic();
21+
});
22+
23+
app.del(function () {
24+
myImportantLogic();
25+
});
26+
27+
app.del("/old", () => {
28+
myImportantLogic();
29+
});
30+
31+
function noModify() {
32+
let a
33+
34+
app.del(a)
35+
}
36+
37+
const myImportantLogic = () => {
38+
console.log("making sure it's there");
39+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/codemod-com/codemod/refs/heads/main/schemas/workflow.json
2+
3+
version: "1"
4+
5+
nodes:
6+
- id: apply-transforms
7+
name: Apply AST Transformations
8+
type: automatic
9+
runtime:
10+
type: direct
11+
steps:
12+
- name: Migrates usage of the legacy APIs `app.del()` to `app.delete()`
13+
js-ast-grep:
14+
js_file: src/workflow.ts
15+
base_path: .
16+
semantic_analysis: file
17+
include:
18+
- "**/*.cjs"
19+
- "**/*.js"
20+
- "**/*.jsx"
21+
- "**/*.mjs"
22+
- "**/*.cts"
23+
- "**/*.mts"
24+
- "**/*.ts"
25+
- "**/*.tsx"
26+
exclude:
27+
- "**/node_modules/**"
28+
language: typescript

package-lock.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)