diff --git a/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-cache-time.input.tsx b/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-cache-time.input.tsx new file mode 100644 index 0000000000..5415e17367 --- /dev/null +++ b/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-cache-time.input.tsx @@ -0,0 +1,81 @@ +import * as React from 'react' +import { QueryClient, useInfiniteQuery } from '@tanstack/react-query' +import { search } from './algolia' + +// Since the `cacheTime` property is string literal and not computed, the codemod should change it. +export type UseAlgoliaOptionsButWithStringLiterals = { + 'indexName': string + 'query': string + 'hitsPerPage'?: number + 'staleTime'?: number + 'cacheTime'?: number + 'enabled'?: boolean +} + +// Since the `cacheTime` property is an identifier and not computed, the codemod should change it. +export type UseAlgoliaOptions = { + indexName: string + query: string + hitsPerPage?: number + staleTime?: number + cacheTime?: number + enabled?: boolean +} + +// Since the `cacheTime` property is an identifier and not computed, and shorthand, the codemod should change it. +export function useAlgolia({ + indexName, + query, + hitsPerPage = 10, + staleTime, + cacheTime, + enabled, +}: UseAlgoliaOptions) { + const queryInfo = useInfiniteQuery({ + queryKey: ['algolia', indexName, query, hitsPerPage], + queryFn: ({ pageParam }) => + search({ indexName, query, pageParam, hitsPerPage }), + defaultPageParam: 0, + getNextPageParam: (lastPage) => lastPage?.nextPage, + staleTime, + cacheTime, + enabled, + }) + + const hits = queryInfo.data?.pages.map((page) => page.hits).flat() + + return { ...queryInfo, hits } +} + +// Since the `cacheTime` property is an identifier and not computed, the codemod should change it. +export const asIdentifierExample = () => + new QueryClient({ + defaultOptions: { + queries: { + cacheTime: 1000 * 60 * 60 * 24, // 24 hours + }, + }, + }) + +// Since the `cacheTime` property is a string literal and not computed, the codemod should change it. +export const asStringLiteralExample = () => + new QueryClient({ + defaultOptions: { + queries: { + 'cacheTime': 1000 * 60 * 60 * 24, // 24 hours + }, + }, + }) + +// Since the `cacheTime` property is computed, the codemod shouldn't touch this example. +export const asComputedExample = () => { + const cacheTime = 'foo' + + return new QueryClient({ + defaultOptions: { + queries: { + [cacheTime]: 1000 * 60 * 60 * 24, // 24 hours + }, + }, + }) +} diff --git a/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-cache-time.output.tsx b/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-cache-time.output.tsx new file mode 100644 index 0000000000..0fd3efde6b --- /dev/null +++ b/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-cache-time.output.tsx @@ -0,0 +1,81 @@ +import * as React from 'react' +import { QueryClient, useInfiniteQuery } from '@tanstack/react-query' +import { search } from './algolia' + +// Since the `cacheTime` property is string literal and not computed, the codemod should change it. +export type UseAlgoliaOptionsButWithStringLiterals = { + 'indexName': string + 'query': string + 'hitsPerPage'?: number + 'staleTime'?: number + 'gcTime'?: number + 'enabled'?: boolean +} + +// Since the `cacheTime` property is an identifier and not computed, the codemod should change it. +export type UseAlgoliaOptions = { + indexName: string + query: string + hitsPerPage?: number + staleTime?: number + gcTime?: number + enabled?: boolean +} + +// Since the `cacheTime` property is an identifier and not computed, and shorthand, the codemod should change it. +export function useAlgolia({ + indexName, + query, + hitsPerPage = 10, + staleTime, + gcTime, + enabled, +}: UseAlgoliaOptions) { + const queryInfo = useInfiniteQuery({ + queryKey: ['algolia', indexName, query, hitsPerPage], + queryFn: ({ pageParam }) => + search({ indexName, query, pageParam, hitsPerPage }), + defaultPageParam: 0, + getNextPageParam: (lastPage) => lastPage?.nextPage, + staleTime, + gcTime, + enabled, + }) + + const hits = queryInfo.data?.pages.map((page) => page.hits).flat() + + return { ...queryInfo, hits } +} + +// Since the `cacheTime` property is an identifier and not computed, the codemod should change it. +export const asIdentifierExample = () => + new QueryClient({ + defaultOptions: { + queries: { + gcTime: 1000 * 60 * 60 * 24, // 24 hours + }, + }, + }) + +// Since the `cacheTime` property is a string literal and not computed, the codemod should change it. +export const asStringLiteralExample = () => + new QueryClient({ + defaultOptions: { + queries: { + 'gcTime': 1000 * 60 * 60 * 24, // 24 hours + }, + }, + }) + +// Since the `cacheTime` property is computed, the codemod shouldn't touch this example. +export const asComputedExample = () => { + const cacheTime = 'foo' + + return new QueryClient({ + defaultOptions: { + queries: { + [cacheTime]: 1000 * 60 * 60 * 24, // 24 hours + }, + }, + }) +} diff --git a/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-use-error-boundary.input.tsx b/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-use-error-boundary.input.tsx new file mode 100644 index 0000000000..e4fee86080 --- /dev/null +++ b/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-use-error-boundary.input.tsx @@ -0,0 +1,44 @@ +import * as React from 'react' + +// Since the `useErrorBoundary` property is string literal and not computed, the codemod should change it. +export type Type1 = { + 'useErrorBoundary'?: boolean +} + +// Since the `useErrorBoundary` property is an identifier and not computed, the codemod should change it. +export type Type2 = { + useErrorBoundary?: boolean +} + +// Since the `useErrorBoundary` property is an identifier and not computed, and shorthand, the codemod should change it. +export function useSomething() { + const queryInfo = useSomethingElse({ + useErrorBoundary, + enabled, + }) + + return queryInfo +} + +// Since the `useErrorBoundary` property is an identifier and not computed, the codemod should change it. +export const asIdentifierExample = () => { + return { + useErrorBoundary: true + } +} + +// Since the `useErrorBoundary` property is a string literal and not computed, the codemod should change it. +export const asStringLiteralExample = () => { + return { + 'useErrorBoundary': true + } +} + +// Since the `useErrorBoundary` property is computed, the codemod shouldn't touch this example. +export const asComputedExample = () => { + const useErrorBoundary = 'foo' + + return { + [useErrorBoundary]: false + } +} diff --git a/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-use-error-boundary.output.tsx b/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-use-error-boundary.output.tsx new file mode 100644 index 0000000000..5c6c8540f6 --- /dev/null +++ b/packages/codemods/src/v5/rename-properties/__testfixtures__/rename-use-error-boundary.output.tsx @@ -0,0 +1,44 @@ +import * as React from 'react' + +// Since the `useErrorBoundary` property is string literal and not computed, the codemod should change it. +export type Type1 = { + 'throwOnError'?: boolean +} + +// Since the `useErrorBoundary` property is an identifier and not computed, the codemod should change it. +export type Type2 = { + throwOnError?: boolean +} + +// Since the `useErrorBoundary` property is an identifier and not computed, and shorthand, the codemod should change it. +export function useSomething() { + const queryInfo = useSomethingElse({ + throwOnError, + enabled, + }) + + return queryInfo +} + +// Since the `useErrorBoundary` property is an identifier and not computed, the codemod should change it. +export const asIdentifierExample = () => { + return { + throwOnError: true + }; +} + +// Since the `useErrorBoundary` property is a string literal and not computed, the codemod should change it. +export const asStringLiteralExample = () => { + return { + 'throwOnError': true + }; +} + +// Since the `useErrorBoundary` property is computed, the codemod shouldn't touch this example. +export const asComputedExample = () => { + const useErrorBoundary = 'foo' + + return { + [useErrorBoundary]: false + } +} diff --git a/packages/codemods/src/v5/rename-properties/__tests__/rename-properties.test.js b/packages/codemods/src/v5/rename-properties/__tests__/rename-properties.test.js new file mode 100644 index 0000000000..31a14fdfa2 --- /dev/null +++ b/packages/codemods/src/v5/rename-properties/__tests__/rename-properties.test.js @@ -0,0 +1,10 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const defineTest = require('jscodeshift/dist/testUtils').defineTest + +defineTest(__dirname, 'rename-properties', null, 'rename-cache-time', { + parser: 'tsx', +}) + +defineTest(__dirname, 'rename-properties', null, 'rename-use-error-boundary', { + parser: 'tsx', +}) diff --git a/packages/codemods/src/v5/rename-properties/rename-properties.js b/packages/codemods/src/v5/rename-properties/rename-properties.js new file mode 100644 index 0000000000..3213be7c7c --- /dev/null +++ b/packages/codemods/src/v5/rename-properties/rename-properties.js @@ -0,0 +1,41 @@ +module.exports = (file, api) => { + const jscodeshift = api.jscodeshift + const root = jscodeshift(file.source) + + const baseRenameLogic = (kind, from, to) => { + root + .find(kind, (node) => { + return ( + node.computed === false && + (node.key?.name === from || node.key?.value === from) + ) + }) + .replaceWith(({ node: mutableNode }) => { + if (mutableNode.key.name !== undefined) { + mutableNode.key.name = to + } + + if (mutableNode.key.value !== undefined) { + mutableNode.key.value = to + } + + return mutableNode + }) + } + + const renameObjectProperty = (from, to) => { + baseRenameLogic(jscodeshift.ObjectProperty, from, to) + } + + const renameTypeScriptPropertySignature = (from, to) => { + baseRenameLogic(jscodeshift.TSPropertySignature, from, to) + } + + renameObjectProperty('cacheTime', 'gcTime') + renameObjectProperty('useErrorBoundary', 'throwOnError') + + renameTypeScriptPropertySignature('cacheTime', 'gcTime') + renameTypeScriptPropertySignature('useErrorBoundary', 'throwOnError') + + return root.toSource({ quote: 'single', lineTerminator: '\n' }) +}