Skip to content

Commit

Permalink
Add input/output types mapping to CLIENT_REQ_RESP_TYPES_MAP (#579)
Browse files Browse the repository at this point in the history
  • Loading branch information
trivikr committed Sep 14, 2023
1 parent 14b438b commit 531767c
Show file tree
Hide file tree
Showing 6 changed files with 27,790 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changeset/neat-dolls-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"aws-sdk-js-codemod": minor
---

Create input/output types mapping in CLIENT_REQ_RESP_TYPES_MAP
89 changes: 89 additions & 0 deletions scripts/generateClientTypesMap/getClientReqRespTypesMap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import jscodeshift, {
Identifier,
TSFunctionType,
TSQualifiedName,
TSTypeReference,
} from "jscodeshift";

import { getTypesSource } from "./getTypesSource";

export const getClientReqRespTypesMap = async (
clientName: string
): Promise<Record<string, string>> => {
const clientTypesMap = {};

const j = jscodeshift.withParser("ts");
const source = getTypesSource(j, clientName);

source.find(j.ClassDeclaration, { id: { name: clientName } }).forEach((classDeclaration) => {
const classMethods = j(classDeclaration).find(j.TSDeclareMethod).nodes();

classMethods.forEach((classMethod) => {
if (classMethod.key.type !== "Identifier") return;
if (classMethod.key.name === "constructor") return;
if (classMethod.key.name.startsWith("waitFor")) return;

const classMethodKeyName = (classMethod.key as Identifier).name;
const commandName = classMethodKeyName.charAt(0).toUpperCase() + classMethodKeyName.slice(1);

if (classMethod.params.length !== 2) return;
if (classMethod.params[0].type !== "Identifier") return;
if (classMethod.params[0].name !== "params") return;

const params = classMethod.params[0] as Identifier;

if (!params.typeAnnotation) return;
if (!params.typeAnnotation.typeAnnotation) return;
if (params.typeAnnotation.typeAnnotation.type !== "TSTypeReference") return;
const paramsTypeRef = params.typeAnnotation!.typeAnnotation! as TSTypeReference;

if (!paramsTypeRef.typeName) return;
if (paramsTypeRef.typeName.type !== "TSQualifiedName") return;
const paramsTypeRefName = paramsTypeRef.typeName as TSQualifiedName;

if (!paramsTypeRefName.right) return;
if (paramsTypeRefName.right.type !== "Identifier") return;
const paramsTypeName = paramsTypeRefName.right as Identifier;
const requestTypeName = paramsTypeName.name;

clientTypesMap[requestTypeName] = `${commandName}CommandInput`;

if (classMethod.params[1].type !== "Identifier") return;
if (classMethod.params[1].name !== "callback") return;
const callback = classMethod.params[1] as Identifier;

if (!callback.typeAnnotation) return;
if (!callback.typeAnnotation.typeAnnotation) return;
if (callback.typeAnnotation.typeAnnotation.type !== "TSFunctionType") return;
const callbackTypeRef = callback.typeAnnotation!.typeAnnotation! as TSFunctionType;

if (!callbackTypeRef.parameters) return;
if (callbackTypeRef.parameters.length !== 2) return;
if (callbackTypeRef.parameters[1].type !== "Identifier") return;
const responseType = callbackTypeRef.parameters[1] as Identifier;

if (!responseType.typeAnnotation) return;
if (responseType.typeAnnotation.type !== "TSTypeAnnotation") return;
if (!responseType.typeAnnotation.typeAnnotation) return;
if (responseType.typeAnnotation.typeAnnotation.type !== "TSTypeReference") return;
const responseTypeRef = responseType.typeAnnotation!.typeAnnotation! as TSTypeReference;

if (!responseTypeRef.typeName) return;
if (responseTypeRef.typeName.type !== "TSQualifiedName") return;
const responseTypeRefName = responseTypeRef.typeName as TSQualifiedName;

if (!responseTypeRefName.right) return;
if (responseTypeRefName.right.type !== "Identifier") return;
const responseTypeName = (responseTypeRefName.right as Identifier).name;

clientTypesMap[responseTypeName] = `${commandName}CommandOutput`;
});
});

return Object.entries(clientTypesMap)
.sort(([key1], [key2]) => key1.localeCompare(key2))
.reduce((obj, [key, value]) => {
obj[key] = value;
return obj;
}, {});
};
14 changes: 2 additions & 12 deletions scripts/generateClientTypesMap/getClientTypesMap.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { readFile } from "fs/promises";
import { join } from "path";
import jscodeshift, { Identifier, TSArrayType, TSTypeLiteral, TSTypeReference } from "jscodeshift";

import { DOCUMENT_CLIENT } from "../../src/transforms/v2-to-v3/config";
import { getClientTypesMapWithKeysRemovedFromValues } from "./getClientTypesMapWithKeysRemovedFromValues";
import { getTypesSource } from "./getTypesSource";

const TYPES_TO_SKIP = ["apiVersion", "ClientConfiguration"];
const ElementTypeToNativeTypeMap = {
Expand All @@ -16,16 +14,8 @@ const ElementTypeToNativeTypeMap = {
export const getClientTypesMap = async (clientName: string): Promise<Record<string, string>> => {
const clientTypesMap = {};

const typesPath =
clientName === DOCUMENT_CLIENT
? join("node_modules", "aws-sdk", "lib", "dynamodb", `document_client.d.ts`)
: join("node_modules", "aws-sdk", "clients", `${clientName.toLowerCase()}.d.ts`);
const relativeTypesPath = join(__dirname, "..", "..", typesPath);

const typesCode = await readFile(relativeTypesPath, "utf8");

const j = jscodeshift.withParser("ts");
const source = j(typesCode);
const source = getTypesSource(j, clientName);

source.find(j.TSModuleDeclaration, { id: { name: clientName } }).forEach((moduleDeclaration) => {
const tsTypes = j(moduleDeclaration).find(j.TSTypeAliasDeclaration).nodes();
Expand Down
16 changes: 16 additions & 0 deletions scripts/generateClientTypesMap/getTypesSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { readFileSync } from "fs";
import { join } from "path";
import { JSCodeshift } from "jscodeshift";
import { DOCUMENT_CLIENT } from "../../src/transforms/v2-to-v3/config";

export const getTypesSource = (j: JSCodeshift, clientName: string) => {
const typesPath =
clientName === DOCUMENT_CLIENT
? join("node_modules", "aws-sdk", "lib", "dynamodb", `document_client.d.ts`)
: join("node_modules", "aws-sdk", "clients", `${clientName.toLowerCase()}.d.ts`);
const relativeTypesPath = join(__dirname, "..", "..", typesPath);

const typesCode = readFileSync(relativeTypesPath, "utf8");

return j(typesCode);
};
42 changes: 24 additions & 18 deletions scripts/generateClientTypesMap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,40 @@ import {
DYNAMODB,
DYNAMODB_DOCUMENT_CLIENT,
} from "../../src/transforms/v2-to-v3/config";
import { getClientReqRespTypesMap } from "./getClientReqRespTypesMap";
import { getClientTypesMap } from "./getClientTypesMap";

const codegenComment = `// This file is generated by scripts/generateClientTypesMap/index.ts
// Do not edit this file directly. Instead, edit the script and run it to regenerate this file.`;

const filePath = join("src", "transforms", "v2-to-v3", "config", "CLIENT_TYPES_MAP.ts");
const relativeFilePath = join(__dirname, "..", "..", filePath);

(async () => {
let fileContent = codegenComment;
for (const [mapName, getTypesMap] of [
["CLIENT_TYPES_MAP", getClientTypesMap],
["CLIENT_REQ_RESP_TYPES_MAP", getClientReqRespTypesMap],
] as [string, (clientName: string) => Promise<Record<string, string>>][]) {
const filePath = join("src", "transforms", "v2-to-v3", "config", `${mapName}.ts`);
const relativeFilePath = join(__dirname, "..", "..", filePath);

let fileContent = codegenComment;

fileContent += `\n\n/* eslint-disable @typescript-eslint/naming-convention */`;
fileContent += `\nexport const CLIENT_TYPES_MAP: Record<string, Record<string, string>> = `;
fileContent += `\n\n/* eslint-disable @typescript-eslint/naming-convention */`;
fileContent += `\nexport const ${mapName}: Record<string, Record<string, string>> = `;

const clientTypesMap = {};
const clientTypesMap = {};

for (const clientName of CLIENT_NAMES) {
clientTypesMap[clientName] = await getClientTypesMap(clientName);
if (clientName === DYNAMODB) {
clientTypesMap[DYNAMODB_DOCUMENT_CLIENT] = await getClientTypesMap(DOCUMENT_CLIENT);
for (const clientName of CLIENT_NAMES) {
clientTypesMap[clientName] = await getTypesMap(clientName);
if (clientName === DYNAMODB) {
clientTypesMap[DYNAMODB_DOCUMENT_CLIENT] = await getTypesMap(DOCUMENT_CLIENT);
}
}
}

fileContent += JSON.stringify(clientTypesMap);
fileContent += `;\n`;
fileContent += JSON.stringify(clientTypesMap);
fileContent += `;\n`;

await writeFile(
relativeFilePath,
await format(fileContent, { parser: "typescript", printWidth: 100 })
);
await writeFile(
relativeFilePath,
await format(fileContent, { parser: "typescript", printWidth: 100 })
);
}
})();
Loading

0 comments on commit 531767c

Please sign in to comment.