-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generate CLIENT_TYPES_MAP by processing client types from v2 (#313)
- Loading branch information
Showing
6 changed files
with
24,507 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"aws-sdk-js-codemod": patch | ||
--- | ||
|
||
Generate CLIENT_TYPES_MAP by processing client types from v2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { readFile } from "fs/promises"; | ||
import jscodeshift, { Identifier, TSArrayType, TSTypeLiteral, TSTypeReference } from "jscodeshift"; | ||
import { join } from "path"; | ||
|
||
const TYPES_TO_SKIP = ["apiVersion", "ClientConfiguration"]; | ||
const ElementTypeToNativeTypeMap = { | ||
TSStringKeyword: "string", | ||
TSNumberKeyword: "number", | ||
TSBooleanKeyword: "boolean", | ||
}; | ||
|
||
export const getClientTypeMap = async (clientName: string): Promise<Record<string, string>> => { | ||
const clientTypesMap = {}; | ||
|
||
const typesPath = 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); | ||
|
||
source.find(j.TSModuleDeclaration, { id: { name: clientName } }).forEach((moduleDeclaration) => { | ||
const tsTypes = j(moduleDeclaration).find(j.TSTypeAliasDeclaration).nodes(); | ||
|
||
for (const [type, value] of Object.entries(ElementTypeToNativeTypeMap)) { | ||
tsTypes | ||
.filter((tsType) => tsType.typeAnnotation.type === type) | ||
.forEach((tsType) => { | ||
clientTypesMap[tsType.id.name] = value; | ||
}); | ||
} | ||
|
||
tsTypes | ||
.filter((tsType) => tsType.typeAnnotation.type === "TSTypeReference") | ||
.forEach((tsType) => { | ||
const name = tsType.id.name; | ||
const typeName = ((tsType.typeAnnotation as TSTypeReference).typeName as Identifier).name; | ||
if (typeName === "Date") { | ||
clientTypesMap[name] = typeName; | ||
} else if (typeName === "EventStream") { | ||
// Exception for SelectObjectContentEventStream | ||
clientTypesMap[name] = "AsyncIterable<KEY>"; | ||
} else { | ||
console.log("TSTypeReference with unsupported type:", name, typeName); | ||
} | ||
}); | ||
|
||
tsTypes | ||
.filter((tsType) => tsType.typeAnnotation.type === "TSUnionType") | ||
.forEach((tsType) => { | ||
const name = tsType.id.name; | ||
if (name.endsWith("Blob")) { | ||
clientTypesMap[name] = "Uint8Array"; | ||
} | ||
}); | ||
|
||
tsTypes | ||
.filter((tsType) => tsType.typeAnnotation.type === "TSArrayType") | ||
.forEach((tsType) => { | ||
const name = tsType.id.name; | ||
const elementType = (tsType.typeAnnotation as TSArrayType).elementType; | ||
if (elementType.type === "TSTypeReference") { | ||
const typeName = elementType.typeName; | ||
if (typeName.type === "Identifier") { | ||
if (clientTypesMap[typeName.name]) { | ||
clientTypesMap[name] = `Array<${clientTypesMap[typeName.name]}>`; | ||
} else { | ||
// Assume it's an interface which would be available in v3. | ||
clientTypesMap[name] = `Array<${typeName.name}>`; | ||
} | ||
} else { | ||
console.log("TSArrayType TSTypeReference without Identifier type:", name); | ||
} | ||
} else if (Object.keys(ElementTypeToNativeTypeMap).includes(elementType.type)) { | ||
clientTypesMap[name] = `Array<${ElementTypeToNativeTypeMap[elementType.type]}>`; | ||
} else { | ||
console.log("TSArrayType with unsupported elemental type:", name); | ||
} | ||
}); | ||
|
||
tsTypes | ||
.filter((tsType) => tsType.typeAnnotation.type === "TSTypeLiteral") | ||
.forEach((tsType) => { | ||
const name = tsType.id.name; | ||
const member = (tsType.typeAnnotation as TSTypeLiteral).members[0]; | ||
if (member.type === "TSIndexSignature") { | ||
if (member.typeAnnotation) { | ||
if (member.typeAnnotation.typeAnnotation) { | ||
const typeAnnotation = member.typeAnnotation.typeAnnotation; | ||
if (typeAnnotation.type === "TSTypeReference") { | ||
const typeName = typeAnnotation.typeName; | ||
if (typeName.type === "Identifier") { | ||
if (clientTypesMap[typeName.name]) { | ||
clientTypesMap[name] = `Record<string, ${clientTypesMap[typeName.name]}>`; | ||
} else { | ||
// Assume it's an interface which would be available in v3. | ||
clientTypesMap[name] = `Record<string, ${typeName.name}>`; | ||
} | ||
} else { | ||
console.log("TSTypeLiteral TSTypeReference without Identifier type:", name); | ||
} | ||
} else if (Object.keys(ElementTypeToNativeTypeMap).includes(typeAnnotation.type)) { | ||
clientTypesMap[name] = `Record<string, ${ | ||
ElementTypeToNativeTypeMap[typeAnnotation.type] | ||
}>`; | ||
} else { | ||
console.log("TSTypeLiteral with unsupported typeAnnotation type:", name); | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
|
||
tsTypes.forEach((tsType) => { | ||
const name = tsType.id.name; | ||
const type = tsType.typeAnnotation.type; | ||
if (!TYPES_TO_SKIP.includes(name) && !clientTypesMap[name] && type !== "TSUnionType") { | ||
console.log("Unsupported type:", name); | ||
} | ||
}); | ||
}); | ||
|
||
return Object.entries(clientTypesMap) | ||
.sort(([key1], [key2]) => key1.localeCompare(key2)) | ||
.reduce((obj, [key, value]) => { | ||
obj[key] = value; | ||
return obj; | ||
}, {}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { writeFile } from "fs/promises"; | ||
import { join } from "path"; | ||
import { format } from "prettier"; | ||
|
||
import { CLIENT_NAMES } from "../../src/transforms/v2-to-v3/config"; | ||
import { getClientTypeMap } from "./getClientTypeMap"; | ||
|
||
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; | ||
|
||
fileContent += `\n\n/* eslint-disable @typescript-eslint/naming-convention */`; | ||
fileContent += `\nexport const CLIENT_TYPES_MAP: Record<string, Record<string, string>> = `; | ||
|
||
const clientTypesMap = {}; | ||
|
||
for (const clientName of CLIENT_NAMES) { | ||
clientTypesMap[clientName] = await getClientTypeMap(clientName); | ||
} | ||
|
||
fileContent += JSON.stringify(clientTypesMap); | ||
fileContent += `;\n`; | ||
|
||
await writeFile(relativeFilePath, format(fileContent, { parser: "typescript", printWidth: 100 })); | ||
})(); |
Oops, something went wrong.