Skip to content

Commit a711101

Browse files
committed
feat: add package.json Express v5 codemod
1 parent b41f6e6 commit a711101

13 files changed

Lines changed: 151 additions & 2 deletions

codemods/v5-migration-recipe/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ This codemod migration recipe helps you update your Express.js v4 applications t
44

55
Included transformations:
66

7+
- **Package JSON Dependencies**: Updates existing `express` and `@types/express` package entries in `package.json` for Express.js v5 migrations.
78
- **Back Redirect Deprecated**: This transformation updates instances of `res.redirect('back')` and `res.location('back')` to use the recommended alternatives. Registry entry: [https://app.codemod.com/registry/@expressjs/back-redirect-deprecated](https://app.codemod.com/registry/@expressjs/back-redirect-deprecated).
89
- **Explicit Request Params**: Migrates usage of the legacy API `req.param(name)` to the current recommended alternatives. Registry entry: [https://app.codemod.com/registry/@expressjs/explicit-request-params](https://app.codemod.com/registry/@expressjs/explicit-request-params).
910
- **Pluralize Method Names**: Migrates deprecated singular request methods to their pluralized counterparts where applicable. Registry entry: [https://app.codemod.com/registry/@expressjs/pluralize-method-names](https://app.codemod.com/registry/@expressjs/pluralize-method-names).

codemods/v5-migration-recipe/codemod.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ category: migration
1010

1111
targets:
1212
languages:
13+
- json
1314
- javascript
1415
- typescript
1516

@@ -23,4 +24,4 @@ keywords:
2324

2425
registry:
2526
access: public
26-
visibility: public
27+
visibility: public

codemods/v5-migration-recipe/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
"version": "1.0.0",
55
"description": "This codemod migration recipe helps you update your Express.js v4 applications to be compatible with Express.js v5 by addressing deprecated APIs.",
66
"type": "module",
7+
"scripts": {
8+
"test": "npx codemod jssg test -l json ./src/package-json.ts ./"
9+
},
710
"repository": {
811
"type": "git",
912
"url": "git+https://github.com/expressjs/codemod.git",
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type Json from '@codemod.com/jssg-types/src/langs/json'
2+
import type { Edit, SgRoot } from '@codemod.com/jssg-types/src/main'
3+
4+
const EXPRESS_V5 = '^5.0.0'
5+
const EXPRESS_TYPES_V5 = '^5.0.0'
6+
const DEPENDENCY_SECTIONS = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'] as const
7+
8+
type PackageJson = {
9+
[key: string]: unknown
10+
}
11+
12+
function isRecord(value: unknown): value is Record<string, unknown> {
13+
return typeof value === 'object' && value !== null && !Array.isArray(value)
14+
}
15+
16+
function updateDependency(dependencies: unknown, packageName: string, version: string): boolean {
17+
if (!isRecord(dependencies)) {
18+
return false
19+
}
20+
21+
if (Object.hasOwn(dependencies, packageName) && dependencies[packageName] !== version) {
22+
dependencies[packageName] = version
23+
return true
24+
}
25+
26+
return false
27+
}
28+
29+
function detectIndent(source: string): string | number {
30+
const match = source.match(/\n([ \t]+)"/)
31+
32+
return match?.[1] ?? 2
33+
}
34+
35+
async function transform(root: SgRoot<Json>): Promise<string | null> {
36+
const rootNode = root.root()
37+
const source = rootNode.text()
38+
let packageJson: PackageJson
39+
40+
try {
41+
packageJson = JSON.parse(source) as PackageJson
42+
} catch {
43+
return null
44+
}
45+
46+
let changed = false
47+
48+
for (const section of DEPENDENCY_SECTIONS) {
49+
const dependencies = packageJson[section]
50+
changed = updateDependency(dependencies, 'express', EXPRESS_V5) || changed
51+
changed = updateDependency(dependencies, '@types/express', EXPRESS_TYPES_V5) || changed
52+
}
53+
54+
if (!changed) {
55+
return null
56+
}
57+
58+
const nextSource = `${JSON.stringify(packageJson, null, detectIndent(source))}${source.endsWith('\n') ? '\n' : ''}`
59+
const edits: Edit[] = [rootNode.replace(nextSource)]
60+
61+
return rootNode.commitEdits(edits)
62+
}
63+
64+
export default transform
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "express-app",
3+
"dependencies": {
4+
"body-parser": "^1.20.3",
5+
"express": "^5.0.0"
6+
},
7+
"devDependencies": {
8+
"@types/express": "^5.0.0",
9+
"typescript": "^5.7.2"
10+
}
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "dev-only",
3+
"devDependencies": {
4+
"express": "^5.0.0"
5+
}
6+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "no-express",
3+
"dependencies": {
4+
"koa": "^2.15.3"
5+
},
6+
"devDependencies": {
7+
"typescript": "^5.7.2"
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "express-plugin",
3+
"peerDependencies": {
4+
"express": "^5.0.0"
5+
},
6+
"optionalDependencies": {
7+
"@types/express": "^5.0.0"
8+
}
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "express-app",
3+
"dependencies": {
4+
"body-parser": "^1.20.3",
5+
"express": "^4.18.2"
6+
},
7+
"devDependencies": {
8+
"@types/express": "^4.17.21",
9+
"typescript": "^5.7.2"
10+
}
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "dev-only",
3+
"devDependencies": {
4+
"express": "~4.21.0"
5+
}
6+
}

0 commit comments

Comments
 (0)