-
-
Notifications
You must be signed in to change notification settings - Fork 11
feat(req-param): migrate req-param to codemod.com #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4cb2b1a
dc86e47
8a48274
9732e6e
da47868
d2c3363
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Migrate legacy `req.param(name)` | ||
|
|
||
| The `req.param(name)` helper that used to magically look up values from multiple places has been removed. This potentially confusing and dangerous method of retrieving form data has been removed. You will now need to specifically look for the submitted parameter name in the `req.params`, `req.body`, or `req.query` object. | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Replacing `req.param('body')` and `req.param('query')` | ||
|
|
||
| Replace `req.param('body')` with `req.body` and | ||
| `req.param('query')` with `req.query`. | ||
|
|
||
| ```diff | ||
| app.get('/', (req, res) => { | ||
| // Before | ||
| - const reqBody = req.param('body'); | ||
| - const reqQuery = req.param('query'); | ||
| // After | ||
| + const reqBody = req.body; | ||
| + const reqQuery = req.query; | ||
| }); | ||
| ``` | ||
|
|
||
| ### Replacing `req.param('paramName')` | ||
|
|
||
| Replace `req.param('paramName')` with `req.params.paramName`. | ||
|
|
||
| ```diff | ||
| app.get('/user/:id', (req, res) => { | ||
| // Before | ||
| - const userId = req.param('id'); | ||
| // After | ||
| + const userId = req.params.id; | ||
| }); | ||
| ``` | ||
|
|
||
| ## References | ||
|
|
||
| - [Migration of `req.param()`](https://expressjs.com/en/guide/migrating-5.html#req.param) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| schema_version: "1.0" | ||
| name: "@expressjs/explicit-request-params" | ||
| version: "1.0.0" | ||
| description: Migrates usage of the legacy APIs `req.param(name)` to the current recommended approaches | ||
| author: bjohansebas (Sebastian Beltran) | ||
| license: MIT | ||
| workflow: workflow.yaml | ||
| repository: "https://github.com/expressjs/codemod/tree/HEAD/codemods/explicit-request-params" | ||
| category: migration | ||
|
|
||
| targets: | ||
| languages: | ||
| - javascript | ||
| - typescript | ||
|
|
||
| keywords: | ||
| - transformation | ||
| - migration | ||
| - express | ||
| - params | ||
|
|
||
| registry: | ||
| access: public | ||
| visibility: public |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "name": "@expressjs/explicit-request-params", | ||
| "private": true, | ||
| "version": "1.0.0", | ||
| "description": "Migrates usage of the legacy APIs `req.param(name)` to the current recommended approaches.", | ||
| "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/explicit-request-params", | ||
| "bugs": "https://github.com/expressjs/codemod/issues" | ||
| }, | ||
| "author": "bjohansebas (Sebastian Beltran)", | ||
| "license": "MIT", | ||
| "homepage": "https://github.com/expressjs/codemod/blob/main/codemods/explicit-request-params/README.md", | ||
| "devDependencies": { | ||
| "@codemod.com/jssg-types": "^1.3.1" | ||
| } | ||
| } | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically, this code is repeated from the previous codemods, probably could be factored out into a utils package, though I'm wondering how this would behave for codemod registration, being a separate package and not published to npm
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a local npm workspace will be bundled by the codemod cli. !the ci have to |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import type Js from '@codemod.com/jssg-types/src/langs/javascript' | ||
| import type { Edit, SgNode, SgRoot } from '@codemod.com/jssg-types/src/main' | ||
|
|
||
| function getStringLiteralValue(node: SgNode<Js>): string | null { | ||
| if (!node.is('string')) return null | ||
|
|
||
| const fragments = node.findAll({ rule: { kind: 'string_fragment' } }) | ||
| if (fragments.length !== 1) return null | ||
| return fragments[0]?.text() ?? null | ||
| } | ||
|
|
||
| function findParentFunctionParameters(node: SgNode<Js>): SgNode<Js, 'formal_parameters'> | null { | ||
| let parent = node.parent() | ||
| while (parent) { | ||
| if (parent.is('formal_parameters')) return parent | ||
| parent = parent.parent() | ||
| } | ||
| return null | ||
| } | ||
|
|
||
| async function transform(root: SgRoot<Js>): Promise<string | null> { | ||
| const rootNode = root.root() | ||
|
|
||
| const nodes = rootNode.findAll({ | ||
| rule: { | ||
| pattern: '$OBJ.$METHOD($ARG)', | ||
| }, | ||
| constraints: { | ||
| METHOD: { regex: '^(param)$' }, | ||
| }, | ||
| }) | ||
|
|
||
bjohansebas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (!nodes.length) return null | ||
|
|
||
| const edits: Edit[] = [] | ||
|
|
||
| for (const call of nodes) { | ||
| const arg = call.getMatch('ARG') | ||
| const obj = call.getMatch('OBJ') | ||
|
|
||
| if (!arg || !obj) continue | ||
| const objDef = obj.definition({ resolveExternal: false }) | ||
| if (!objDef) continue | ||
|
|
||
| const isParameter = objDef.node.matches({ | ||
| rule: { inside: { kind: 'formal_parameters', stopBy: 'end' } }, | ||
| }) | ||
| if (!isParameter) continue | ||
|
|
||
| const parameters = findParentFunctionParameters(objDef.node) | ||
| if (!parameters) continue | ||
| const firstParameter = parameters.find({ rule: { kind: 'identifier' } }) | ||
|
|
||
| if (!firstParameter) continue | ||
| const requestName = firstParameter.text() | ||
|
|
||
| const argValue = getStringLiteralValue(arg) | ||
|
|
||
| if (argValue === 'body') { | ||
| edits.push(call.replace(`${requestName}.body`)) | ||
| } else if (argValue === 'query') { | ||
| edits.push(call.replace(`${requestName}.query`)) | ||
| } else if (argValue) { | ||
| edits.push(call.replace(`${requestName}.params.${argValue}`)) | ||
| } | ||
| } | ||
|
|
||
| if (!edits.length) return null | ||
|
|
||
| return rootNode.commitEdits(edits) | ||
| } | ||
|
|
||
| export default transform | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import express from "express"; | ||
|
|
||
| const app = express(); | ||
|
|
||
| app.get("/", function (req, res) { | ||
| const reqBody = req.body; | ||
| const reqQuery = req.query; | ||
| const reqQueryTest = req.query.test; | ||
| const reqOther = req.params.other; | ||
| const reqOtherNested = req.params.other.nested; | ||
| }); | ||
|
|
||
| app.get("/", function (request, response) { | ||
| const reqBody = request.body; | ||
| const reqQuery = request.query; | ||
| const reqQueryTest = request.query.test; | ||
| const reqOther = request.params.other; | ||
| const reqOtherNested = request.params.other.nested; | ||
| }); | ||
|
|
||
| app.get("/", (req, res) => { | ||
| const reqBody = req.body; | ||
| const reqQuery = req.query; | ||
| const reqQueryTest = req.query.test; | ||
| const reqOther = req.params.other; | ||
| const reqOtherNested = req.params.other.nested; | ||
| }); | ||
|
|
||
| app.get("/", (request, response) => { | ||
| const reqBody = request.body; | ||
| const reqQuery = request.query; | ||
| const reqQueryTest = request.query.test; | ||
| const reqOther = request.params.other; | ||
| const reqOtherNested = request.params.other.nested; | ||
| }); | ||
|
|
||
| app.param(function () { | ||
| // my important logic | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import express from "express"; | ||
|
|
||
| const app = express(); | ||
|
|
||
| app.get("/", function (req, res) { | ||
| const reqBody = req.param('body'); | ||
| const reqQuery = req.param('query'); | ||
| const reqQueryTest = req.param('query').test; | ||
| const reqOther = req.param('other'); | ||
| const reqOtherNested = req.param('other').nested; | ||
| }); | ||
|
|
||
| app.get("/", function (request, response) { | ||
| const reqBody = request.param('body'); | ||
| const reqQuery = request.param('query'); | ||
| const reqQueryTest = request.param('query').test; | ||
| const reqOther = request.param('other'); | ||
| const reqOtherNested = request.param('other').nested; | ||
| }); | ||
|
|
||
| app.get("/", (req, res) => { | ||
| const reqBody = req.param('body'); | ||
| const reqQuery = req.param('query'); | ||
| const reqQueryTest = req.param('query').test; | ||
| const reqOther = req.param('other'); | ||
| const reqOtherNested = req.param('other').nested; | ||
| }); | ||
|
|
||
| app.get("/", (request, response) => { | ||
| const reqBody = request.param('body'); | ||
| const reqQuery = request.param('query'); | ||
| const reqQueryTest = request.param('query').test; | ||
| const reqOther = request.param('other'); | ||
| const reqOtherNested = request.param('other').nested; | ||
| }); | ||
|
|
||
| app.param(function () { | ||
| // my important logic | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 `req.param(name)` to the current recommended approaches | ||
| 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 |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, I'm setting this to private so we don't accidentally publish this to npm, but does this affect codemod registration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
codemod cli don't care about package.json