Skip to content

Commit e14a171

Browse files
feat(codemod): add codemod that renames the Hydrate component usages to HydrationBoundary usages (#5761)
1 parent c254fec commit e14a171

File tree

6 files changed

+145
-0
lines changed

6 files changed

+145
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from 'react'
2+
import {
3+
Hydrate,
4+
QueryClient,
5+
QueryClientProvider,
6+
} from '@tanstack/react-query'
7+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
8+
9+
export default function MyApp({ Component, pageProps }) {
10+
const [queryClient] = React.useState(() => new QueryClient())
11+
12+
return (
13+
<QueryClientProvider client={queryClient}>
14+
<Hydrate state={pageProps.dehydratedState}>
15+
<Component {...pageProps} />
16+
</Hydrate>
17+
<ReactQueryDevtools />
18+
</QueryClientProvider>
19+
)
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from 'react'
2+
import {
3+
HydrationBoundary,
4+
QueryClient,
5+
QueryClientProvider,
6+
} from '@tanstack/react-query'
7+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
8+
9+
export default function MyApp({ Component, pageProps }) {
10+
const [queryClient] = React.useState(() => new QueryClient())
11+
12+
return (
13+
(<QueryClientProvider client={queryClient}>
14+
<HydrationBoundary state={pageProps.dehydratedState}>
15+
<Component {...pageProps} />
16+
</HydrationBoundary>
17+
<ReactQueryDevtools />
18+
</QueryClientProvider>)
19+
);
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from 'react'
2+
import {
3+
Hydrate as RenamedHydrate,
4+
QueryClient as RenamedQueryClient,
5+
QueryClientProvider as RenamedQueryClientProvider,
6+
} from '@tanstack/react-query'
7+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
8+
9+
export default function MyApp({ Component, pageProps }) {
10+
const [queryClient] = React.useState(() => new RenamedQueryClient())
11+
12+
return (
13+
<RenamedQueryClientProvider client={queryClient}>
14+
<RenamedHydrate state={pageProps.dehydratedState}>
15+
<Component {...pageProps} />
16+
</RenamedHydrate>
17+
<ReactQueryDevtools />
18+
</RenamedQueryClientProvider>
19+
)
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from 'react'
2+
import {
3+
HydrationBoundary as RenamedHydrate,
4+
QueryClient as RenamedQueryClient,
5+
QueryClientProvider as RenamedQueryClientProvider,
6+
} from '@tanstack/react-query'
7+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
8+
9+
export default function MyApp({ Component, pageProps }) {
10+
const [queryClient] = React.useState(() => new RenamedQueryClient())
11+
12+
return (
13+
<RenamedQueryClientProvider client={queryClient}>
14+
<RenamedHydrate state={pageProps.dehydratedState}>
15+
<Component {...pageProps} />
16+
</RenamedHydrate>
17+
<ReactQueryDevtools />
18+
</RenamedQueryClientProvider>
19+
)
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// eslint-disable-next-line @typescript-eslint/no-var-requires
2+
const defineTest = require('jscodeshift/dist/testUtils').defineTest
3+
4+
defineTest(__dirname, 'rename-hydrate', null, 'default-import', {
5+
parser: 'tsx',
6+
})
7+
8+
defineTest(__dirname, 'rename-hydrate', null, 'named-import', {
9+
parser: 'tsx',
10+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module.exports = (file, api) => {
2+
const jscodeshift = api.jscodeshift
3+
const root = jscodeshift(file.source)
4+
5+
const importSpecifiers = root
6+
.find(jscodeshift.ImportDeclaration, {
7+
source: {
8+
value: '@tanstack/react-query',
9+
},
10+
})
11+
.find(jscodeshift.ImportSpecifier, {
12+
imported: {
13+
name: 'Hydrate',
14+
},
15+
})
16+
17+
if (importSpecifiers.length > 0) {
18+
const names = {
19+
searched: 'Hydrate', // By default, we want to replace the `Hydrate` usages.
20+
target: 'HydrationBoundary', // We want to replace them with `HydrationBoundary`.
21+
}
22+
23+
importSpecifiers.replaceWith(({ node: mutableNode }) => {
24+
/**
25+
* When the local and imported names match which means the code doesn't contain import aliases, we need
26+
* to replace only the import specifier.
27+
* @type {boolean}
28+
*/
29+
const usesDefaultImport =
30+
mutableNode.local.name === mutableNode.imported.name
31+
32+
if (!usesDefaultImport) {
33+
// If the code uses import aliases, we must re-use the alias.
34+
names.searched = mutableNode.local.name
35+
names.target = mutableNode.local.name
36+
}
37+
38+
// Override the import specifier.
39+
mutableNode.imported.name = 'HydrationBoundary'
40+
41+
return mutableNode
42+
})
43+
44+
root
45+
.findJSXElements(names.searched)
46+
.replaceWith(({ node: mutableNode }) => {
47+
mutableNode.openingElement.name.name = names.target
48+
mutableNode.closingElement.name.name = names.target
49+
50+
return mutableNode
51+
})
52+
}
53+
54+
return root.toSource({ quote: 'single', lineTerminator: '\n' })
55+
}

0 commit comments

Comments
 (0)