Created
August 14, 2024 03:42
-
-
Save evanpurkhiser/83f2f0098f7b215894342903bd3b02d6 to your computer and use it in GitHub Desktop.
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
import { readFileSync } from "node:fs"; | |
import type { API, FileInfo } from "jscodeshift"; | |
const typeFiles = [ | |
"alerts", | |
"auth", | |
"breadcrumbs", | |
"controlSiloOrganization", | |
"core", | |
"debugFiles", | |
"debugImage", | |
"echarts", | |
"event", | |
"experiments", | |
"group", | |
"hooks", | |
"index", | |
"integrations", | |
"metrics", | |
"notificationActions", | |
"onboarding", | |
"organization", | |
"project", | |
"relay", | |
"release", | |
"sampling", | |
"sandbox", | |
"sessions", | |
"sourceMaps", | |
"stacktrace", | |
"system", | |
"user", | |
"utils", | |
"views", | |
]; | |
let identifierToTypeFile: Record<string, string> | null = null; | |
export default function transformer(file: FileInfo, api: API) { | |
const j = api.jscodeshift; | |
// Create the mapping of type identifiers to the type file they belong to. We | |
// only need to do this once so store it in a global variable once we're done | |
if (identifierToTypeFile === null) { | |
const sentryRoot = "/Users/evan/Coding/sentry/static/app/"; | |
const identifiersPerType = typeFiles.map((typeFile) => { | |
const ast = j( | |
readFileSync(`${sentryRoot}types/${typeFile}.tsx`, { | |
encoding: "utf8", | |
flag: "r", | |
}), | |
); | |
const identifiers: string[] = []; | |
ast.find(j.ExportNamedDeclaration).forEach((path) => { | |
if (!path.node.declaration) { | |
return; | |
} | |
if ( | |
"id" in path.node.declaration && | |
path.node.declaration.id && | |
"name" in path.node.declaration.id | |
) { | |
identifiers.push(path.node.declaration.id.name); | |
} | |
}); | |
return [typeFile, identifiers] as const; | |
}); | |
identifierToTypeFile = Object.fromEntries( | |
identifiersPerType.flatMap(([typeFile, identifiers]) => | |
identifiers.map((id) => [id, typeFile]), | |
), | |
); | |
} | |
// Find type imports in every file and break them apart into multiple | |
const ast = j(file.source); | |
const typeImport = ast | |
.find(j.ImportDeclaration) | |
.filter((path) => path.node.source.value === "sentry/types"); | |
typeImport.forEach((path) => { | |
const typeGroups: Record<string, string[]> = {}; | |
path.node.specifiers?.forEach((s) => { | |
const id = s.type === "ImportSpecifier" ? s.imported.name : undefined; | |
const typeFile = id ? identifierToTypeFile?.[id] : undefined; | |
if (id === undefined || typeFile === undefined) { | |
console.log(`TYPE MISSING FILE MAPPING: ${id}`); | |
return; | |
} | |
typeGroups[typeFile] ??= []; | |
typeGroups[typeFile].push(id); | |
}); | |
const imports = Object.entries(typeGroups).map(([typeFile, imports]) => | |
j.importDeclaration( | |
imports.map((i) => j.importSpecifier(j.identifier(i))), | |
j.stringLiteral(`sentry/types/${typeFile}`), | |
), | |
); | |
const first = imports.shift(); | |
// Replace the `sentry/types` import with the first and add the rest after | |
path.replace(first); | |
imports.forEach((i) => path.insertAfter(i)); | |
}); | |
return ast.toSource(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment