Skip to content

Commit 8e20937

Browse files
authored
feat(sendfile): add migration for res.sendfile to res.sendFile (#98)
* feat(sendfile): add migration for res.sendfile to res.sendFile * fix(package): update repository directory and homepage in package.json * fix: update package-lock * rename codemod * Update codemods/camelcase-sendfile/codemod.yaml Signed-off-by: Sebastian Beltran <bjohansebas@gmail.com> * fix(workflow): simplify empty checks for nodes and edits --------- Signed-off-by: Sebastian Beltran <bjohansebas@gmail.com>
1 parent 325f04d commit 8e20937

8 files changed

Lines changed: 277 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 `res.sendfile(file)` to `res.sendFile(file)`
2+
3+
Migrates usage of the legacy APIs `res.sendfile(file)` to `res.sendFile(file)`.
4+
5+
## Example
6+
7+
### Migrating `res.sendfile(file)`
8+
9+
The migration involves replacing instances of `res.sendfile(file)` with `res.sendFile(file)`.
10+
11+
```diff
12+
app.get('/some-route', (req, res) => {
13+
// Some logic here
14+
- res.sendfile('/path/to/file');
15+
+ res.sendFile('/path/to/file');
16+
});
17+
```
18+
19+
## References
20+
21+
- [Migration of res.sendfile(file)](https://expressjs.com/en/guide/migrating-5.html#res.sendFile)
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/camelcase-sendfile"
3+
version: "1.0.0"
4+
description: Migrates usage of the legacy API `res.sendfile(file)` to `res.sendFile(file)`
5+
author: bjohansebas (Sebastian Beltran)
6+
license: MIT
7+
workflow: workflow.yaml
8+
repository: "https://github.com/expressjs/codemod/tree/HEAD/codemods/camelcase-sendfile"
9+
category: migration
10+
11+
targets:
12+
languages:
13+
- javascript
14+
- typescript
15+
16+
keywords:
17+
- transformation
18+
- migration
19+
- express
20+
- sendFile
21+
- files
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/camelcase-sendfile",
3+
"private": true,
4+
"version": "1.0.0",
5+
"description": "Migrates usage of the legacy API `res.sendfile(file)` to `res.sendFile(file)`.",
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/camelcase-sendfile",
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/camelcase-sendfile/README.md",
19+
"devDependencies": {
20+
"@codemod.com/jssg-types": "^1.3.1"
21+
}
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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($$$METHOD)',
10+
},
11+
constraints: {
12+
METHOD: { regex: '^(sendfile)$' },
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 obj = call.getMatch('OBJ')
23+
if (!method || !obj) continue
24+
25+
const objDef = obj.definition({ resolveExternal: false })
26+
if (!objDef) continue
27+
28+
edits.push(method.replace('sendFile'))
29+
}
30+
31+
if (!edits.length) return null
32+
return rootNode.commitEdits(edits)
33+
}
34+
35+
export default transform
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import express from "express";
2+
import path from "path";
3+
import sendfile from "other-place"
4+
5+
const app = express();
6+
const options = {
7+
root: path.join(__dirname, 'public'),
8+
dotfiles: 'deny',
9+
headers: {
10+
'x-timestamp': Date.now(),
11+
'x-sent': true
12+
}
13+
}
14+
15+
const sharedSendFile = (res, next, fileName) => {
16+
res.sendFile(fileName, options, (err) => {
17+
if (err) {
18+
next(err)
19+
} else {
20+
console.log('Sent:', fileName)
21+
}
22+
})
23+
}
24+
25+
app.get('/file/:name', (req, res, next) => {
26+
res.sendFile()
27+
})
28+
29+
app.get('/file/:name', (req, res, next) => {
30+
res.sendFile("file.txt")
31+
})
32+
33+
app.get('/file/:name', (req, res, next) => {
34+
const fileName = req.params.name
35+
36+
res.sendFile(fileName, options, (err) => {
37+
if (err) {
38+
next(err)
39+
} else {
40+
console.log('Sent:', fileName)
41+
}
42+
})
43+
sharedSendFile(res, next, fileName);
44+
})
45+
46+
app.get('/filename/:name', function (req, res, next) {
47+
const fileName = req.params.name
48+
49+
res.sendFile(fileName, options, (err) => {
50+
if (err) {
51+
next(err)
52+
} else {
53+
console.log('Sent:', fileName)
54+
}
55+
})
56+
sharedSendFile(res, next, fileName);
57+
})
58+
59+
app.get('/file-handler', (req, res, next) => {
60+
sendfile('test', options, (err) => {
61+
if (err) {
62+
next(err)
63+
} else {
64+
console.log('Sent:', 'test')
65+
}
66+
})
67+
})
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import express from "express";
2+
import path from "path";
3+
import sendfile from "other-place"
4+
5+
const app = express();
6+
const options = {
7+
root: path.join(__dirname, 'public'),
8+
dotfiles: 'deny',
9+
headers: {
10+
'x-timestamp': Date.now(),
11+
'x-sent': true
12+
}
13+
}
14+
15+
const sharedSendFile = (res, next, fileName) => {
16+
res.sendfile(fileName, options, (err) => {
17+
if (err) {
18+
next(err)
19+
} else {
20+
console.log('Sent:', fileName)
21+
}
22+
})
23+
}
24+
25+
app.get('/file/:name', (req, res, next) => {
26+
res.sendfile()
27+
})
28+
29+
app.get('/file/:name', (req, res, next) => {
30+
res.sendfile("file.txt")
31+
})
32+
33+
app.get('/file/:name', (req, res, next) => {
34+
const fileName = req.params.name
35+
36+
res.sendfile(fileName, options, (err) => {
37+
if (err) {
38+
next(err)
39+
} else {
40+
console.log('Sent:', fileName)
41+
}
42+
})
43+
sharedSendFile(res, next, fileName);
44+
})
45+
46+
app.get('/filename/:name', function (req, res, next) {
47+
const fileName = req.params.name
48+
49+
res.sendfile(fileName, options, (err) => {
50+
if (err) {
51+
next(err)
52+
} else {
53+
console.log('Sent:', fileName)
54+
}
55+
})
56+
sharedSendFile(res, next, fileName);
57+
})
58+
59+
app.get('/file-handler', (req, res, next) => {
60+
sendfile('test', options, (err) => {
61+
if (err) {
62+
next(err)
63+
} else {
64+
console.log('Sent:', 'test')
65+
}
66+
})
67+
})
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 `res.sendfile(file)` to `res.sendFile(file)`
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)