diff --git a/codemods/pluralize-method-names/README.md b/codemods/pluralize-method-names/README.md new file mode 100644 index 0000000..f345f23 --- /dev/null +++ b/codemods/pluralize-method-names/README.md @@ -0,0 +1,44 @@ +# Migrate pluralized request methods + +Migrates deprecated request methods to their pluralized versions that were deprecated in Express 4 and removed in Express 5. + +## Example + +### Migrating `req.acceptsCharset(charset)` + +The migration involves replacing instances of `req.acceptsCharset(charset)` with `req.acceptsCharsets(charset)`. + +```diff +app.get('/', (req, res) => { +- const charset = req.acceptsCharset('utf-8'); ++ const charset = req.acceptsCharsets('utf-8'); + res.json({ charset }); +}); +``` +### Migrating `req.acceptsEncoding(encoding) + +The migration involves replacing instances of `req.acceptsEncoding(encoding)` with `req.acceptsEncodings(encoding)`. + +```diff +app.get('/', (req, res) => { +- const encoding = req.acceptsEncoding('gzip'); ++ const encoding = req.acceptsEncodings('gzip'); + res.json({ encoding }); +}); +``` + +### Migrating `req.acceptsLanguage(language)` + +The migration involves replacing instances of `req.acceptsLanguage(language)` with `req.acceptsLanguages(language)`. + +```diff +app.get('/', (req, res) => { +- const language = req.acceptsLanguage('en'); ++ const language = req.acceptsLanguages('en'); + res.json({ language }); +}); +``` + +## References + +- [Migration of pluralized request methods](https://expressjs.com/en/guide/migrating-5.html#plural) diff --git a/codemods/pluralize-method-names/codemod.yaml b/codemods/pluralize-method-names/codemod.yaml new file mode 100644 index 0000000..56ba749 --- /dev/null +++ b/codemods/pluralize-method-names/codemod.yaml @@ -0,0 +1,27 @@ +schema_version: "1.0" +name: "@expressjs/pluralize-method-names" +version: "1.0.0" +description: Migrates usage of deprecated singular request methods to their pluralized versions in Express.js applications. +author: bjohansebas (Sebastian Beltran) +license: MIT +workflow: workflow.yaml +repository: "https://github.com/expressjs/codemod/tree/HEAD/codemods/pluralize-method-names" +category: migration + +targets: + languages: + - javascript + - typescript + +keywords: + - transformation + - migration + - express + - accepts + - accepetsCharsets + - acceptsEncodings + - acceptsLanguages + +registry: + access: public + visibility: public \ No newline at end of file diff --git a/codemods/pluralize-method-names/package.json b/codemods/pluralize-method-names/package.json new file mode 100644 index 0000000..1c3cd1c --- /dev/null +++ b/codemods/pluralize-method-names/package.json @@ -0,0 +1,22 @@ +{ + "name": "@expressjs/pluralize-method-names", + "private": true, + "version": "1.0.0", + "description": "Migrates usage of deprecated singular request methods to their pluralized versions in Express.js applications.", + "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/pluralize-method-names", + "bugs": "https://github.com/expressjs/codemod/issues" + }, + "author": "bjohansebas (Sebastian Beltran)", + "license": "MIT", + "homepage": "https://github.com/expressjs/codemod/blob/main/codemods/pluralize-method-names/README.md", + "devDependencies": { + "@codemod.com/jssg-types": "^1.3.1" + } +} diff --git a/codemods/pluralize-method-names/src/workflow.ts b/codemods/pluralize-method-names/src/workflow.ts new file mode 100644 index 0000000..1baf93a --- /dev/null +++ b/codemods/pluralize-method-names/src/workflow.ts @@ -0,0 +1,41 @@ +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: { + any: [ + { pattern: '$OBJ.$METHOD($ARG)' }, + { + pattern: '$OBJ.$METHOD()', + }, + ], + }, + constraints: { + METHOD: { regex: '^(acceptsCharset|acceptsEncoding|acceptsLanguage)$' }, + }, + }) + + if (!nodes.length) return null + + const edits: Edit[] = [] + + for (const call of nodes) { + const method = call.getMatch('METHOD') + const obj = call.getMatch('OBJ') + if (!obj || !method) continue + + const objDef = obj.definition({ resolveExternal: false }) + if (!objDef) continue + + edits.push(method.replace(`${method.text()}s`)) + } + + if (!edits.length) return null + + return rootNode.commitEdits(edits) +} + +export default transform diff --git a/codemods/pluralize-method-names/tests/expected/charset.ts b/codemods/pluralize-method-names/tests/expected/charset.ts new file mode 100644 index 0000000..73713dd --- /dev/null +++ b/codemods/pluralize-method-names/tests/expected/charset.ts @@ -0,0 +1,19 @@ +import express from 'express' + +const app = express() + +app.get('/', (req, res) => { + const charset = req.acceptsCharsets(); + res.json({ charset }); +}); + + +app.get('/', (req, res) => { + const charset = req.acceptsCharsets('utf-8'); + res.json({ charset }); +}); + +app.get('/', function (request, response) { + const charset = request.acceptsCharsets('utf-8'); + response.json({ charset }); +}); \ No newline at end of file diff --git a/codemods/pluralize-method-names/tests/expected/encoding.ts b/codemods/pluralize-method-names/tests/expected/encoding.ts new file mode 100644 index 0000000..bf2c3f4 --- /dev/null +++ b/codemods/pluralize-method-names/tests/expected/encoding.ts @@ -0,0 +1,18 @@ +import express from 'express' + +const app = express() + +app.get('/', (req, res) => { + const encoding = req.acceptsEncodings(); + res.json({ encoding }); +}); + +app.get('/', (req, res) => { + const encoding = req.acceptsEncodings('gzip'); + res.json({ encoding }); +}); + +app.get('/', function (request, response) { + const encoding = request.acceptsEncodings('gzip'); + response.json({ encoding }); +}); \ No newline at end of file diff --git a/codemods/pluralize-method-names/tests/expected/language.ts b/codemods/pluralize-method-names/tests/expected/language.ts new file mode 100644 index 0000000..5c4f2b9 --- /dev/null +++ b/codemods/pluralize-method-names/tests/expected/language.ts @@ -0,0 +1,18 @@ +import express from 'express' + +const app = express() + +app.get('/', (req, res) => { + const encoding = req.acceptsLanguages(); + res.json({ encoding }); +}); + +app.get('/', (req, res) => { + const encoding = req.acceptsLanguages('gzip'); + res.json({ encoding }); +}); + +app.get('/', function (request, response) { + const encoding = request.acceptsLanguages('gzip'); + response.json({ encoding }); +}); \ No newline at end of file diff --git a/codemods/pluralize-method-names/tests/input/charset.ts b/codemods/pluralize-method-names/tests/input/charset.ts new file mode 100644 index 0000000..5e7c962 --- /dev/null +++ b/codemods/pluralize-method-names/tests/input/charset.ts @@ -0,0 +1,19 @@ +import express from 'express' + +const app = express() + +app.get('/', (req, res) => { + const charset = req.acceptsCharset(); + res.json({ charset }); +}); + + +app.get('/', (req, res) => { + const charset = req.acceptsCharset('utf-8'); + res.json({ charset }); +}); + +app.get('/', function (request, response) { + const charset = request.acceptsCharset('utf-8'); + response.json({ charset }); +}); \ No newline at end of file diff --git a/codemods/pluralize-method-names/tests/input/encoding.ts b/codemods/pluralize-method-names/tests/input/encoding.ts new file mode 100644 index 0000000..fa130ca --- /dev/null +++ b/codemods/pluralize-method-names/tests/input/encoding.ts @@ -0,0 +1,18 @@ +import express from 'express' + +const app = express() + +app.get('/', (req, res) => { + const encoding = req.acceptsEncoding(); + res.json({ encoding }); +}); + +app.get('/', (req, res) => { + const encoding = req.acceptsEncoding('gzip'); + res.json({ encoding }); +}); + +app.get('/', function (request, response) { + const encoding = request.acceptsEncoding('gzip'); + response.json({ encoding }); +}); \ No newline at end of file diff --git a/codemods/pluralize-method-names/tests/input/language.ts b/codemods/pluralize-method-names/tests/input/language.ts new file mode 100644 index 0000000..a719ed3 --- /dev/null +++ b/codemods/pluralize-method-names/tests/input/language.ts @@ -0,0 +1,18 @@ +import express from 'express' + +const app = express() + +app.get('/', (req, res) => { + const encoding = req.acceptsLanguage(); + res.json({ encoding }); +}); + +app.get('/', (req, res) => { + const encoding = req.acceptsLanguage('gzip'); + res.json({ encoding }); +}); + +app.get('/', function (request, response) { + const encoding = request.acceptsLanguage('gzip'); + response.json({ encoding }); +}); \ No newline at end of file diff --git a/codemods/pluralize-method-names/workflow.yaml b/codemods/pluralize-method-names/workflow.yaml new file mode 100644 index 0000000..4dcf1d6 --- /dev/null +++ b/codemods/pluralize-method-names/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 deprecated singular request methods to their pluralized versions in Express.js applications. + 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 diff --git a/package-lock.json b/package-lock.json index 93ec2b5..cb10744 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,6 +64,14 @@ "@codemod.com/jssg-types": "^1.3.1" } }, + "codemods/pluralize-method-names": { + "name": "@expressjs/pluralize-method-names", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@codemod.com/jssg-types": "^1.3.1" + } + }, "codemods/status-send-order": { "name": "@expressjs/status-send-order", "version": "1.0.0", @@ -1037,6 +1045,10 @@ "resolved": "codemods/camelcase-sendfile", "link": true }, + "node_modules/@expressjs/pluralize-method-names": { + "resolved": "codemods/pluralize-method-names", + "link": true + }, "node_modules/@expressjs/status-send-order": { "resolved": "codemods/status-send-order", "link": true