From 5fb11bb463a45fc1cbab6b532cfdf21c6182563e Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:48:14 -0700 Subject: [PATCH] Transform checks for error.code to error.name in promise catch (#810) --- .changeset/lemon-days-dress.md | 5 + .../aws-error-name/global-import.input.js | 35 +++++- .../aws-error-name/global-import.input.ts | 40 ++++++- .../aws-error-name/global-import.output.js | 33 +++++- .../aws-error-name/global-import.output.ts | 38 +++++- .../aws-error-name/service-import.input.js | 35 +++++- .../aws-error-name/service-import.input.ts | 38 +++++- .../aws-error-name/service-import.output.js | 33 +++++- .../aws-error-name/service-import.output.ts | 36 +++++- .../v2-to-v3/apis/renameErrorCodeWithName.ts | 109 +++++++++++++----- 10 files changed, 345 insertions(+), 57 deletions(-) create mode 100644 .changeset/lemon-days-dress.md diff --git a/.changeset/lemon-days-dress.md b/.changeset/lemon-days-dress.md new file mode 100644 index 00000000..ee23e324 --- /dev/null +++ b/.changeset/lemon-days-dress.md @@ -0,0 +1,5 @@ +--- +"aws-sdk-js-codemod": patch +--- + +Transform checks for error.code to error.name in promise catch diff --git a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.input.js b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.input.js index 711905cb..2ed183d8 100644 --- a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.input.js +++ b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.input.js @@ -1,15 +1,42 @@ import AWS from "aws-sdk"; const client = new AWS.S3(); +const Bucket = "bucket-name"; try { - await client.createBucket({ - Bucket: "bucket" - }).promise(); + await client.createBucket({ Bucket }).promise(); } catch (error) { if (error.code === "BucketAlreadyExists") { // Handle BucketAlreadyExists error } else { throw error; } -} \ No newline at end of file +} + +client + .createBucket({ Bucket }) + .promise() + .then((response) => { + // Consume the response + }) + .catch((error) => { + if (error.code === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); + +client + .createBucket({ Bucket }) + .promise() + .then((response) => { + // Consume the response + }) + .catch(function (error) { + if (error.code === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); diff --git a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.input.ts b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.input.ts index d15d0636..aee65a15 100644 --- a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.input.ts +++ b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.input.ts @@ -1,10 +1,10 @@ import AWS from "aws-sdk"; -export const func = async (client: AWS.S3) => { +const Bucket = "bucket-name"; + +export const funcTryCatch = async (client: AWS.S3) => { try { - await client.createBucket({ - Bucket: "bucket" - }).promise(); + await client.createBucket({ Bucket }).promise(); } catch (error) { if (error.code === "BucketAlreadyExists") { // Handle BucketAlreadyExists error @@ -12,4 +12,36 @@ export const func = async (client: AWS.S3) => { throw error; } } +} + +export const funcPromiseCatchArrowFn = async (client: AWS.S3) => { + client + .createBucket({ Bucket }) + .promise() + .then((response) => { + // Consume the response + }) + .catch((error) => { + if (error.code === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); +} + +export const funcPromiseCatchFn = async (client: AWS.S3) => { + client + .createBucket({ Bucket }) + .promise() + .then((response) => { + // Consume the response + }) + .catch(function (error) { + if (error.code === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); } \ No newline at end of file diff --git a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.output.js b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.output.js index 357bd9ae..76f99267 100644 --- a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.output.js +++ b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.output.js @@ -1,15 +1,40 @@ import { S3 } from "@aws-sdk/client-s3"; const client = new S3(); +const Bucket = "bucket-name"; try { - await client.createBucket({ - Bucket: "bucket" - }); + await client.createBucket({ Bucket }); } catch (error) { if (error.name === "BucketAlreadyExists") { // Handle BucketAlreadyExists error } else { throw error; } -} \ No newline at end of file +} + +client + .createBucket({ Bucket }) + .then((response) => { + // Consume the response + }) + .catch((error) => { + if (error.name === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); + +client + .createBucket({ Bucket }) + .then((response) => { + // Consume the response + }) + .catch(function (error) { + if (error.name === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); \ No newline at end of file diff --git a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.output.ts b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.output.ts index 9e211bc0..87078c87 100644 --- a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.output.ts +++ b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/global-import.output.ts @@ -1,10 +1,10 @@ import { S3 } from "@aws-sdk/client-s3"; -export const func = async (client: S3) => { +const Bucket = "bucket-name"; + +export const funcTryCatch = async (client: S3) => { try { - await client.createBucket({ - Bucket: "bucket" - }); + await client.createBucket({ Bucket }); } catch (error) { if (error.name === "BucketAlreadyExists") { // Handle BucketAlreadyExists error @@ -12,4 +12,34 @@ export const func = async (client: S3) => { throw error; } } +} + +export const funcPromiseCatchArrowFn = async (client: S3) => { + client + .createBucket({ Bucket }) + .then((response) => { + // Consume the response + }) + .catch((error) => { + if (error.name === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); +} + +export const funcPromiseCatchFn = async (client: S3) => { + client + .createBucket({ Bucket }) + .then((response) => { + // Consume the response + }) + .catch(function (error) { + if (error.name === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); } \ No newline at end of file diff --git a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.input.js b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.input.js index 6d373c13..36a79f62 100644 --- a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.input.js +++ b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.input.js @@ -1,15 +1,42 @@ import { S3 } from "aws-sdk"; const client = new S3(); +const Bucket = "bucket-name"; try { - await client.createBucket({ - Bucket: "bucket" - }).promise(); + await client.createBucket({ Bucket }).promise(); } catch (error) { if (error.code === "BucketAlreadyExists") { // Handle BucketAlreadyExists error } else { throw error; } -} \ No newline at end of file +} + +client + .createBucket({ Bucket }) + .promise() + .then((response) => { + // Consume the response + }) + .catch((error) => { + if (error.code === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); + +client + .createBucket({ Bucket }) + .promise() + .then((response) => { + // Consume the response + }) + .catch(function (error) { + if (error.code === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); diff --git a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.input.ts b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.input.ts index f62c1b23..faeaea7c 100644 --- a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.input.ts +++ b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.input.ts @@ -1,10 +1,10 @@ import { S3 } from "aws-sdk"; +const Bucket = "bucket-name"; + export const func = async (client: S3) => { try { - await client.createBucket({ - Bucket: "bucket" - }).promise(); + await client.createBucket({ Bucket }).promise(); } catch (error) { if (error.code === "BucketAlreadyExists") { // Handle BucketAlreadyExists error @@ -12,4 +12,36 @@ export const func = async (client: S3) => { throw error; } } +} + +export const funcPromiseCatchArrowFn = async (client: S3) => { + client + .createBucket({ Bucket }) + .promise() + .then((response) => { + // Consume the response + }) + .catch((error) => { + if (error.code === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); +} + +export const funcPromiseCatchFn = async (client: S3) => { + client + .createBucket({ Bucket }) + .promise() + .then((response) => { + // Consume the response + }) + .catch(function (error) { + if (error.code === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); } \ No newline at end of file diff --git a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.output.js b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.output.js index 357bd9ae..76f99267 100644 --- a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.output.js +++ b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.output.js @@ -1,15 +1,40 @@ import { S3 } from "@aws-sdk/client-s3"; const client = new S3(); +const Bucket = "bucket-name"; try { - await client.createBucket({ - Bucket: "bucket" - }); + await client.createBucket({ Bucket }); } catch (error) { if (error.name === "BucketAlreadyExists") { // Handle BucketAlreadyExists error } else { throw error; } -} \ No newline at end of file +} + +client + .createBucket({ Bucket }) + .then((response) => { + // Consume the response + }) + .catch((error) => { + if (error.name === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); + +client + .createBucket({ Bucket }) + .then((response) => { + // Consume the response + }) + .catch(function (error) { + if (error.name === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); \ No newline at end of file diff --git a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.output.ts b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.output.ts index 9e211bc0..b48f2b67 100644 --- a/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.output.ts +++ b/src/transforms/v2-to-v3/__fixtures__/aws-error-name/service-import.output.ts @@ -1,10 +1,10 @@ import { S3 } from "@aws-sdk/client-s3"; +const Bucket = "bucket-name"; + export const func = async (client: S3) => { try { - await client.createBucket({ - Bucket: "bucket" - }); + await client.createBucket({ Bucket }); } catch (error) { if (error.name === "BucketAlreadyExists") { // Handle BucketAlreadyExists error @@ -12,4 +12,34 @@ export const func = async (client: S3) => { throw error; } } +} + +export const funcPromiseCatchArrowFn = async (client: S3) => { + client + .createBucket({ Bucket }) + .then((response) => { + // Consume the response + }) + .catch((error) => { + if (error.name === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); +} + +export const funcPromiseCatchFn = async (client: S3) => { + client + .createBucket({ Bucket }) + .then((response) => { + // Consume the response + }) + .catch(function (error) { + if (error.name === "BucketAlreadyExists") { + // Handle BucketAlreadyExists error + } else { + // Handle other error. + } + }); } \ No newline at end of file diff --git a/src/transforms/v2-to-v3/apis/renameErrorCodeWithName.ts b/src/transforms/v2-to-v3/apis/renameErrorCodeWithName.ts index 10feedb0..2fe50451 100644 --- a/src/transforms/v2-to-v3/apis/renameErrorCodeWithName.ts +++ b/src/transforms/v2-to-v3/apis/renameErrorCodeWithName.ts @@ -1,7 +1,48 @@ -import { Collection, JSCodeshift, TryStatement } from "jscodeshift"; +import { + ASTPath, + ArrowFunctionExpression, + CallExpression, + Collection, + FunctionExpression, + JSCodeshift, + TryStatement, +} from "jscodeshift"; import { ClientIdentifier } from "../types"; +const renameCodeWithName = ( + j: JSCodeshift, + source: Collection, + errorName: string +): void => { + source + .find(j.MemberExpression, { + object: { type: "Identifier", name: errorName }, + property: { type: "Identifier", name: "code" }, + }) + .replaceWith(() => j.memberExpression(j.identifier(errorName), j.identifier("name"))); +}; + +const getCatchExpression = ( + j: JSCodeshift, + callExpression: ASTPath +): ASTPath | null => { + const parentPath = callExpression.parentPath.value; + if (parentPath?.type !== "MemberExpression") { + return null; + } + + const grandParentPath = callExpression.parentPath.parentPath.value; + if (grandParentPath?.type !== "CallExpression") { + return null; + } + + if (parentPath.property.type === "Identifier" && parentPath.property.name === "catch") { + return callExpression.parentPath.parentPath; + } + return getCatchExpression(j, callExpression.parentPath.parentPath); +}; + // Renames error.code with error.name. export const renameErrorCodeWithName = ( j: JSCodeshift, @@ -9,40 +50,54 @@ export const renameErrorCodeWithName = ( clientIdentifiers: ClientIdentifier[] ): void => { for (const clientId of clientIdentifiers) { - // Replace error.code with error.name in catch clauses. - source - .find(j.CallExpression, { - callee: { - type: "MemberExpression", - object: clientId, - }, - }) - .forEach((callExpression) => { - const tryStatement = j(callExpression).closest(j.TryStatement).nodes()[0] as TryStatement; - - if (!tryStatement || !tryStatement.handler) { + const callExpressions = source.find(j.CallExpression, { + callee: { type: "MemberExpression", object: clientId }, + }); + + // Replace error.code with error.name in try-catch clauses. + callExpressions.forEach((callExpression) => { + const tryStatement = j(callExpression).closest(j.TryStatement).nodes()[0] as TryStatement; + + if (!tryStatement || !tryStatement.handler) { + return; + } + + const catchClause = tryStatement.handler; + const errorParam = catchClause.param; + + if (errorParam?.type !== "Identifier") { + return; + } + + renameCodeWithName(j, j(catchClause.body), errorParam.name); + }); + + // Replace error.code with error.name in promise catch. + callExpressions + .map((callExpression) => getCatchExpression(j, callExpression)) + .forEach((catchExpression) => { + if (!catchExpression) { + return; + } + + if ( + !["ArrowFunctionExpression", "FunctionExpression"].includes( + catchExpression.value.arguments[0].type + ) + ) { return; } - const catchClause = tryStatement.handler; - const errorParam = catchClause.param; + const catchFunction = catchExpression.value.arguments[0] as + | FunctionExpression + | ArrowFunctionExpression; + const errorParam = catchFunction.params[0]; if (errorParam?.type !== "Identifier") { return; } - j(catchClause.body) - .find(j.MemberExpression, { - object: { - type: "Identifier", - name: errorParam.name, - }, - property: { - type: "Identifier", - name: "code", - }, - }) - .replaceWith(() => j.memberExpression(errorParam, j.identifier("name"))); + renameCodeWithName(j, j(catchFunction.body), errorParam.name); }); } };