@trpc/upgrade 0.0.0-alpha.0 → 0.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/cli.cjs +73 -46
- package/dist/transforms/hooksToOptions.cjs +37 -36
- package/dist/transforms/provider.cjs +14 -24
- package/package.json +5 -6
- package/src/bin/cli.ts +151 -74
- package/src/transforms/hooksToOptions.ts +37 -36
- package/src/transforms/provider.ts +17 -33
package/README.md
CHANGED
package/dist/cli.cjs
CHANGED
|
@@ -4,73 +4,100 @@ var cli$1 = require('@effect/cli');
|
|
|
4
4
|
var platform = require('@effect/platform');
|
|
5
5
|
var platformNode = require('@effect/platform-node');
|
|
6
6
|
var effect = require('effect');
|
|
7
|
-
var ignore = require('ignore');
|
|
8
7
|
var typescript = require('typescript');
|
|
9
8
|
|
|
10
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
10
|
|
|
12
11
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
13
|
-
var ignore__default = /*#__PURE__*/_interopDefault(ignore);
|
|
14
12
|
|
|
15
|
-
var version = "0.0.0-alpha.
|
|
13
|
+
var version = "0.0.0-alpha.10";
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
const MakeCommand = (command, ...args)=>{
|
|
16
|
+
console.log('MakeCommand', command, args, process.cwd());
|
|
17
|
+
return platform.Command.workingDirectory(process.cwd())(platform.Command.make(command, ...args));
|
|
18
|
+
};
|
|
19
|
+
const assertCleanGitTree = platform.Command.string(MakeCommand('git', 'status')).pipe().pipe(effect.Effect.filterOrFail(effect.String.includes('nothing to commit'), ()=>'Git tree is not clean, please commit your changes and try again, or run with `--force`'));
|
|
20
|
+
const getPackageManager = ()=>effect.Match.value(process.env.npm_config_user_agent ?? 'npm').pipe(effect.Match.when(effect.String.startsWith('pnpm'), ()=>'pnpm'), effect.Match.when(effect.String.startsWith('yarn'), ()=>'yarn'), effect.Match.when(effect.String.startsWith('bun'), ()=>'bun'), effect.Match.orElse(()=>'npm'));
|
|
18
21
|
const installPackage = (packageName)=>{
|
|
19
|
-
const packageManager =
|
|
20
|
-
return platform.Command.streamLines(
|
|
22
|
+
const packageManager = getPackageManager();
|
|
23
|
+
return platform.Command.streamLines(MakeCommand(packageManager, 'install', packageName)).pipe(effect.Stream.mapEffect(effect.Console.log), effect.Stream.runDrain);
|
|
24
|
+
};
|
|
25
|
+
const uninstallPackage = (packageName)=>{
|
|
26
|
+
const packageManager = getPackageManager();
|
|
27
|
+
const uninstallCmd = packageManager === 'yarn' ? 'remove' : 'uninstall';
|
|
28
|
+
return platform.Command.streamLines(MakeCommand(packageManager, uninstallCmd, packageName)).pipe(effect.Stream.mapEffect(effect.Console.log), effect.Stream.runDrain);
|
|
21
29
|
};
|
|
22
30
|
const filterIgnored = (files)=>effect.Effect.gen(function*() {
|
|
23
|
-
const
|
|
24
|
-
|
|
31
|
+
const ignores = yield* platform.Command.string(MakeCommand('git', 'check-ignore', '**/*')).pipe(effect.Effect.tap(effect.Effect.log), effect.Effect.map((_)=>_.split('\n')));
|
|
32
|
+
yield* effect.Effect.logDebug('All files in program:', files.map((_)=>_.fileName));
|
|
33
|
+
yield* effect.Effect.logDebug('Ignored files:', ignores);
|
|
25
34
|
// Ignore "common files"
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
const filteredSourcePaths = files.filter((source)=>source.fileName.startsWith(path__default.default.resolve()) && // only look ahead of current directory
|
|
36
|
+
!source.fileName.includes('/trpc/packages/') && // relative paths when running codemod locally
|
|
37
|
+
!ignores.includes(source.fileName)).map((source)=>source.fileName);
|
|
38
|
+
yield* effect.Effect.logDebug('Filtered files:', filteredSourcePaths);
|
|
39
|
+
return filteredSourcePaths;
|
|
29
40
|
});
|
|
30
|
-
const
|
|
41
|
+
const TSProgram = effect.Effect.succeed(typescript.findConfigFile(process.cwd(), typescript.sys.fileExists)).pipe(effect.Effect.filterOrFail(effect.Predicate.isNotNullable, ()=>'No tsconfig found'), effect.Effect.tap((_)=>effect.Effect.logDebug('Using tsconfig', _)), effect.Effect.map((_)=>typescript.readConfigFile(_, typescript.sys.readFile)), effect.Effect.map((_)=>typescript.parseJsonConfigFileContent(_.config, typescript.sys, process.cwd())), effect.Effect.map((_)=>typescript.createProgram({
|
|
31
42
|
options: _.options,
|
|
32
43
|
rootNames: _.fileNames,
|
|
33
44
|
configFileParsingDiagnostics: _.errors
|
|
34
45
|
})));
|
|
46
|
+
// FIXME :: hacky
|
|
35
47
|
const transformPath = (path)=>process.env.DEV ? path : path.replace('../', './').replace('.ts', '.cjs');
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
const force = cli$1.Options.boolean('force').pipe(cli$1.Options.withAlias('f'), cli$1.Options.withDefault(false), cli$1.Options.withDescription('Skip git status check, use with caution'));
|
|
49
|
+
/**
|
|
50
|
+
* TODO: Instead of default values these should be detected automatically from the TS program
|
|
51
|
+
*/ const trpcFile = cli$1.Options.text('trpcFile').pipe(cli$1.Options.withAlias('f'), cli$1.Options.withDefault('~/trpc'), cli$1.Options.withDescription('Path to the trpc import file'));
|
|
52
|
+
const trpcImportName = cli$1.Options.text('trpcImportName').pipe(cli$1.Options.withAlias('i'), cli$1.Options.withDefault('trpc'), cli$1.Options.withDescription('Name of the trpc import'));
|
|
53
|
+
const skipTanstackQuery = cli$1.Options.boolean('skipTanstackQuery').pipe(cli$1.Options.withAlias('q'), cli$1.Options.withDefault(false), cli$1.Options.withDescription('Skip installing @trpc/tanstack-react-query package'));
|
|
54
|
+
const verbose = cli$1.Options.boolean('verbose').pipe(cli$1.Options.withAlias('v'), cli$1.Options.withDefault(false), cli$1.Options.withDescription('Enable verbose logging'));
|
|
55
|
+
const rootComamnd = cli$1.Command.make('upgrade', {
|
|
56
|
+
force,
|
|
57
|
+
trpcFile,
|
|
58
|
+
trpcImportName,
|
|
59
|
+
skipTanstackQuery,
|
|
60
|
+
verbose
|
|
61
|
+
}, (args)=>effect.Effect.gen(function*() {
|
|
62
|
+
if (args.verbose) {
|
|
63
|
+
yield* effect.Effect.log('Running upgrade with args:', args);
|
|
46
64
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
65
|
+
if (!args.force) {
|
|
66
|
+
yield* assertCleanGitTree;
|
|
67
|
+
}
|
|
68
|
+
const transforms = yield* effect.pipe(cli$1.Prompt.multiSelect({
|
|
69
|
+
message: 'Select transforms to run',
|
|
70
|
+
choices: [
|
|
71
|
+
{
|
|
72
|
+
title: 'Migrate Hooks to xxxOptions API',
|
|
73
|
+
value: require.resolve(transformPath('../transforms/hooksToOptions.ts'))
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
title: 'Migrate context provider setup',
|
|
77
|
+
value: require.resolve(transformPath('../transforms/provider.ts'))
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}), effect.Effect.flatMap((selected)=>{
|
|
81
|
+
if (selected.length === 0) {
|
|
82
|
+
return effect.Effect.fail(new Error('Please select at least one transform to run'));
|
|
83
|
+
}
|
|
84
|
+
return effect.Effect.succeed(selected);
|
|
85
|
+
}), effect.Effect.map(// Make sure provider transform runs first if it's selected
|
|
86
|
+
effect.Array.sortWith((a)=>!a.includes('provider.ts'), effect.Order.boolean)));
|
|
87
|
+
const program = yield* TSProgram;
|
|
51
88
|
const sourceFiles = program.getSourceFiles();
|
|
52
|
-
// Make sure provider transform runs first if it's selected
|
|
53
|
-
_.sort((a, b)=>a.includes('provider.ts') ? -1 : b.includes('provider.ts') ? 1 : 0);
|
|
54
|
-
/**
|
|
55
|
-
* TODO: Detect these automatically
|
|
56
|
-
*/ const appRouterImportFile = '~/server/routers/_app';
|
|
57
|
-
const appRouterImportName = 'AppRouter';
|
|
58
|
-
const trpcFile = '~/lib/trpc';
|
|
59
|
-
const trpcImportName = 'trpc';
|
|
60
89
|
const commitedFiles = yield* filterIgnored(sourceFiles);
|
|
61
|
-
yield* effect.Effect.forEach(
|
|
62
|
-
return effect.pipe(effect.Effect.log('Running transform', transform), effect.Effect.flatMap(()=>effect.Effect.tryPromise(async ()=>import('jscodeshift/src/Runner.js').then(({ run })=>run(transform.
|
|
63
|
-
appRouterImportFile,
|
|
64
|
-
appRouterImportName,
|
|
65
|
-
trpcFile,
|
|
66
|
-
trpcImportName
|
|
67
|
-
})))), effect.Effect.map((res)=>effect.Effect.log('Transform result', res)));
|
|
90
|
+
yield* effect.Effect.forEach(transforms, (transform)=>{
|
|
91
|
+
return effect.pipe(effect.Effect.log('Running transform', transform), effect.Effect.flatMap(()=>effect.Effect.tryPromise(async ()=>import('jscodeshift/src/Runner.js').then(({ run })=>run(transform, commitedFiles, args)))), effect.Effect.map((_)=>effect.Effect.log('Transform result', _)));
|
|
68
92
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
93
|
+
if (!args.skipTanstackQuery) {
|
|
94
|
+
yield* effect.Effect.log('Installing @trpc/tanstack-react-query');
|
|
95
|
+
yield* installPackage('@trpc/tanstack-react-query');
|
|
96
|
+
yield* effect.Effect.log('Uninstalling @trpc/react-query');
|
|
97
|
+
yield* uninstallPackage('@trpc/react-query');
|
|
98
|
+
}
|
|
99
|
+
}).pipe(effect.Logger.withMinimumLogLevel(args.verbose ? effect.LogLevel.Debug : effect.LogLevel.Info)));
|
|
100
|
+
const cli = cli$1.Command.run(rootComamnd, {
|
|
74
101
|
name: 'tRPC Upgrade CLI',
|
|
75
102
|
version: `v${version}`
|
|
76
103
|
});
|
|
@@ -43,59 +43,50 @@ const utilMap = {
|
|
|
43
43
|
getInfiniteData: 'getInfiniteQueryData'
|
|
44
44
|
};
|
|
45
45
|
function transform(file, api, options) {
|
|
46
|
-
const {
|
|
47
|
-
if (!
|
|
48
|
-
throw new Error('
|
|
46
|
+
const { trpcImportName } = options;
|
|
47
|
+
if (!trpcImportName) {
|
|
48
|
+
throw new Error('trpcImportName is required');
|
|
49
49
|
}
|
|
50
50
|
const j = api.jscodeshift;
|
|
51
51
|
const root = j(file.source);
|
|
52
52
|
let dirtyFlag = false;
|
|
53
53
|
// Traverse all functions, and _do stuff_
|
|
54
54
|
root.find(j.FunctionDeclaration).forEach((path)=>{
|
|
55
|
-
if (j(path).find(j.Identifier, {
|
|
56
|
-
name: trpcImportName
|
|
57
|
-
}).size() > 0) {
|
|
58
|
-
updateTRPCImport(path);
|
|
59
|
-
}
|
|
60
55
|
replaceHooksWithOptions(path);
|
|
61
56
|
removeSuspenseDestructuring(path);
|
|
62
57
|
migrateUseUtils(path);
|
|
63
58
|
});
|
|
64
59
|
root.find(j.ArrowFunctionExpression).forEach((path)=>{
|
|
65
|
-
if (j(path).find(j.Identifier, {
|
|
66
|
-
name: trpcImportName
|
|
67
|
-
}).size() > 0) {
|
|
68
|
-
updateTRPCImport(path);
|
|
69
|
-
}
|
|
70
60
|
replaceHooksWithOptions(path);
|
|
71
61
|
removeSuspenseDestructuring(path);
|
|
72
62
|
migrateUseUtils(path);
|
|
73
63
|
});
|
|
64
|
+
if (dirtyFlag) {
|
|
65
|
+
updateTRPCImport();
|
|
66
|
+
}
|
|
74
67
|
/**
|
|
75
68
|
* === HELPER FUNCTIONS BELOW ===
|
|
76
|
-
*/ function
|
|
77
|
-
const specifier = root.find(j.ImportDeclaration, {
|
|
78
|
-
source: {
|
|
79
|
-
value: trpcFile
|
|
80
|
-
}
|
|
81
|
-
}).find(j.ImportSpecifier, {
|
|
82
|
-
imported: {
|
|
83
|
-
name: trpcImportName
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
if (specifier.size() === 0) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
specifier.replaceWith(j.importSpecifier(j.identifier('useTRPC')));
|
|
90
|
-
dirtyFlag = true;
|
|
69
|
+
*/ function ensureUseTRPCCall(path) {
|
|
91
70
|
const variableDeclaration = j.variableDeclaration('const', [
|
|
92
71
|
j.variableDeclarator(j.identifier(trpcImportName), j.callExpression(j.identifier('useTRPC'), []))
|
|
93
72
|
]);
|
|
94
73
|
if (j.FunctionDeclaration.check(path.node)) {
|
|
95
|
-
|
|
96
|
-
|
|
74
|
+
path.node.body.body.unshift(variableDeclaration);
|
|
75
|
+
dirtyFlag = true;
|
|
97
76
|
} else if (j.BlockStatement.check(path.node.body)) {
|
|
98
77
|
path.node.body.body.unshift(variableDeclaration);
|
|
78
|
+
dirtyFlag = true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function updateTRPCImport() {
|
|
82
|
+
const specifier = root.find(j.ImportSpecifier, {
|
|
83
|
+
imported: {
|
|
84
|
+
name: trpcImportName
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
if (specifier.size() > 0) {
|
|
88
|
+
specifier.replaceWith(j.importSpecifier(j.identifier('useTRPC')));
|
|
89
|
+
dirtyFlag = true;
|
|
99
90
|
}
|
|
100
91
|
}
|
|
101
92
|
function ensureImported(lib, specifier) {
|
|
@@ -114,10 +105,11 @@ function transform(file, api, options) {
|
|
|
114
105
|
dirtyFlag = true;
|
|
115
106
|
}
|
|
116
107
|
}
|
|
117
|
-
function replaceHooksWithOptions(
|
|
108
|
+
function replaceHooksWithOptions(fnPath) {
|
|
118
109
|
// REplace proxy-hooks with useX(options())
|
|
110
|
+
let hasInserted = false;
|
|
119
111
|
for (const [hook, { fn, lib }] of Object.entries(hookToOptions)){
|
|
120
|
-
j(
|
|
112
|
+
j(fnPath).find(j.CallExpression, {
|
|
121
113
|
callee: {
|
|
122
114
|
property: {
|
|
123
115
|
name: hook
|
|
@@ -131,6 +123,10 @@ function transform(file, api, options) {
|
|
|
131
123
|
}
|
|
132
124
|
// Rename the hook to the options function
|
|
133
125
|
memberExpr.property.name = fn;
|
|
126
|
+
if (!hasInserted) {
|
|
127
|
+
ensureUseTRPCCall(fnPath);
|
|
128
|
+
hasInserted = true;
|
|
129
|
+
}
|
|
134
130
|
// Wrap it in the hook call
|
|
135
131
|
j(path).replaceWith(j.callExpression(j.identifier(hook), [
|
|
136
132
|
path.node
|
|
@@ -172,7 +168,7 @@ function transform(file, api, options) {
|
|
|
172
168
|
}
|
|
173
169
|
// Replace util.PATH.proxyMethod() with trpc.PATH.queryFilter()
|
|
174
170
|
const proxyMethod = memberExpr.property.name;
|
|
175
|
-
memberExpr.object.object = j.identifier(
|
|
171
|
+
memberExpr.object.object = j.identifier(trpcImportName);
|
|
176
172
|
memberExpr.property = j.identifier('queryFilter');
|
|
177
173
|
// Wrap it in queryClient.utilMethod()
|
|
178
174
|
j(callExprPath).replaceWith(j.memberExpression(j.identifier('queryClient'), j.callExpression(j.identifier(utilMap[proxyMethod]), [
|
|
@@ -198,11 +194,10 @@ function transform(file, api, options) {
|
|
|
198
194
|
].includes(declarator.init.callee.name)) {
|
|
199
195
|
return;
|
|
200
196
|
}
|
|
201
|
-
console.log(declarator.init.callee.name);
|
|
202
197
|
const tuple = j.ArrayPattern.check(declarator?.id) ? declarator.id : null;
|
|
203
198
|
const dataName = j.Identifier.check(tuple?.elements?.[0]) ? tuple.elements[0].name : null;
|
|
204
199
|
const queryName = j.Identifier.check(tuple?.elements?.[1]) ? tuple.elements[1].name : null;
|
|
205
|
-
if (
|
|
200
|
+
if (queryName) {
|
|
206
201
|
declarator.id = j.identifier(queryName);
|
|
207
202
|
dirtyFlag = true;
|
|
208
203
|
if (dataName) {
|
|
@@ -210,12 +205,18 @@ function transform(file, api, options) {
|
|
|
210
205
|
j.variableDeclarator(j.identifier(dataName), j.memberExpression(declarator.id, j.identifier('data')))
|
|
211
206
|
]));
|
|
212
207
|
}
|
|
208
|
+
} else if (dataName) {
|
|
209
|
+
// const [dataName] = ... => const { data: dataName } = ...
|
|
210
|
+
declarator.id = j.objectPattern([
|
|
211
|
+
j.property('init', j.identifier('data'), j.identifier(dataName))
|
|
212
|
+
]);
|
|
213
|
+
dirtyFlag = true;
|
|
213
214
|
}
|
|
214
215
|
});
|
|
215
216
|
}
|
|
216
217
|
return dirtyFlag ? root.toSource() : undefined;
|
|
217
218
|
}
|
|
218
|
-
const parser = 'tsx';
|
|
219
|
+
const parser = 'tsx';
|
|
219
220
|
|
|
220
221
|
exports.default = transform;
|
|
221
222
|
exports.parser = parser;
|
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
2
|
|
|
3
3
|
function transform(file, api, options) {
|
|
4
|
-
const {
|
|
4
|
+
const { trpcImportName } = options;
|
|
5
|
+
let routerName = undefined;
|
|
5
6
|
const j = api.jscodeshift;
|
|
6
7
|
const root = j(file.source);
|
|
7
8
|
let dirtyFlag = false;
|
|
8
|
-
function upsertAppRouterImport() {
|
|
9
|
-
if (root.find(j.ImportDeclaration, {
|
|
10
|
-
source: {
|
|
11
|
-
value: appRouterImportFile
|
|
12
|
-
}
|
|
13
|
-
}).size() === 0) {
|
|
14
|
-
root.find(j.ImportDeclaration).at(-1).insertAfter(j.importDeclaration([
|
|
15
|
-
j.importSpecifier(j.identifier(appRouterImportName))
|
|
16
|
-
], j.literal(appRouterImportFile), 'type'));
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
9
|
// Find the variable declaration for `trpc`
|
|
20
10
|
root.find(j.VariableDeclaration).forEach((path)=>{
|
|
21
11
|
const declaration = path.node.declarations[0];
|
|
22
12
|
if (j.Identifier.check(declaration.id) && declaration.id.name === trpcImportName) {
|
|
23
13
|
if (j.CallExpression.check(declaration.init) && j.Identifier.check(declaration.init.callee) && declaration.init.callee.name === 'createTRPCReact') {
|
|
14
|
+
// Get router name ( TODO : should probably get this from the TS compiler along with the import path)
|
|
15
|
+
routerName = declaration.init.original?.typeParameters?.params?.[0]?.typeName?.name;
|
|
24
16
|
// Replace the `createTRPCReact` call with `createTRPCContext`
|
|
25
17
|
declaration.init.callee.name = 'createTRPCContext';
|
|
26
18
|
// Destructure the result into `TRPCProvider` and `useTRPC`
|
|
@@ -57,7 +49,7 @@ function transform(file, api, options) {
|
|
|
57
49
|
});
|
|
58
50
|
});
|
|
59
51
|
}
|
|
60
|
-
// Replace trpc.createClient with createTRPCClient
|
|
52
|
+
// Replace trpc.createClient with createTRPCClient<TRouter>
|
|
61
53
|
root.find(j.CallExpression, {
|
|
62
54
|
callee: {
|
|
63
55
|
object: {
|
|
@@ -69,12 +61,12 @@ function transform(file, api, options) {
|
|
|
69
61
|
}
|
|
70
62
|
}).forEach((path)=>{
|
|
71
63
|
path.node.callee = j.identifier('createTRPCClient');
|
|
72
|
-
// Add the type parameter `<AppRouter>`
|
|
73
|
-
path.node.typeParameters = j.tsTypeParameterInstantiation([
|
|
74
|
-
j.tsTypeReference(j.identifier(appRouterImportName))
|
|
75
|
-
]);
|
|
76
|
-
upsertAppRouterImport();
|
|
77
64
|
dirtyFlag = true;
|
|
65
|
+
if (routerName) {
|
|
66
|
+
path.node.typeParameters = j.tsTypeParameterInstantiation([
|
|
67
|
+
j.tsTypeReference(j.identifier(routerName))
|
|
68
|
+
]);
|
|
69
|
+
}
|
|
78
70
|
});
|
|
79
71
|
// Replace <trpc.Provider client={...} with <TRPCProvider trpcClient={...}
|
|
80
72
|
root.find(j.JSXElement, {
|
|
@@ -112,14 +104,12 @@ function transform(file, api, options) {
|
|
|
112
104
|
path.node.specifiers?.push(createTRPCClientImport);
|
|
113
105
|
});
|
|
114
106
|
// Replace trpc import with TRPCProvider
|
|
115
|
-
root.find(j.
|
|
116
|
-
|
|
117
|
-
|
|
107
|
+
root.find(j.ImportSpecifier, {
|
|
108
|
+
imported: {
|
|
109
|
+
name: trpcImportName
|
|
118
110
|
}
|
|
119
111
|
}).forEach((path)=>{
|
|
120
|
-
path.node.
|
|
121
|
-
j.importSpecifier(j.identifier('TRPCProvider'))
|
|
122
|
-
];
|
|
112
|
+
path.node.name = j.identifier('TRPCProvider');
|
|
123
113
|
});
|
|
124
114
|
}
|
|
125
115
|
return dirtyFlag ? root.toSource() : undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trpc/upgrade",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.10",
|
|
4
4
|
"description": "Upgrade scripts for tRPC",
|
|
5
5
|
"author": "juliusmarminge",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,11 +28,10 @@
|
|
|
28
28
|
"!**/__tests__"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@effect/cli": "0.
|
|
32
|
-
"@effect/platform": "0.
|
|
33
|
-
"@effect/platform-node": "0.
|
|
34
|
-
"effect": "3.10
|
|
35
|
-
"ignore": "^6.0.2",
|
|
31
|
+
"@effect/cli": "0.54.4",
|
|
32
|
+
"@effect/platform": "0.75.4",
|
|
33
|
+
"@effect/platform-node": "0.71.4",
|
|
34
|
+
"effect": "3.12.10",
|
|
36
35
|
"jscodeshift": "17.1.1",
|
|
37
36
|
"typescript": "^5.6.2"
|
|
38
37
|
},
|
package/src/bin/cli.ts
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { Command as CLICommand, Prompt } from '@effect/cli';
|
|
4
|
-
import { Command
|
|
3
|
+
import { Command as CLICommand, Options, Prompt } from '@effect/cli';
|
|
4
|
+
import { Command } from '@effect/platform';
|
|
5
5
|
import { NodeContext, NodeRuntime } from '@effect/platform-node';
|
|
6
6
|
import {
|
|
7
|
+
Array,
|
|
7
8
|
Console,
|
|
8
9
|
Effect,
|
|
10
|
+
Logger,
|
|
11
|
+
LogLevel,
|
|
9
12
|
Match,
|
|
13
|
+
Order,
|
|
10
14
|
pipe,
|
|
11
15
|
Predicate,
|
|
12
16
|
Stream,
|
|
13
17
|
String,
|
|
14
18
|
} from 'effect';
|
|
15
|
-
import ignore from 'ignore';
|
|
16
19
|
import type { SourceFile } from 'typescript';
|
|
17
20
|
import {
|
|
18
21
|
createProgram,
|
|
@@ -23,52 +26,76 @@ import {
|
|
|
23
26
|
} from 'typescript';
|
|
24
27
|
import { version } from '../../package.json';
|
|
25
28
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
()
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
);
|
|
29
|
+
const MakeCommand = (command: string, ...args: string[]) => {
|
|
30
|
+
console.log('MakeCommand', command, args, process.cwd());
|
|
31
|
+
return Command.workingDirectory(process.cwd())(
|
|
32
|
+
Command.make(command, ...args),
|
|
33
|
+
);
|
|
34
|
+
};
|
|
33
35
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const assertCleanGitTree = Command.string(MakeCommand('git', 'status'))
|
|
37
|
+
.pipe()
|
|
38
|
+
.pipe(
|
|
39
|
+
Effect.filterOrFail(
|
|
40
|
+
String.includes('nothing to commit'),
|
|
41
|
+
() =>
|
|
42
|
+
'Git tree is not clean, please commit your changes and try again, or run with `--force`',
|
|
43
|
+
),
|
|
44
|
+
);
|
|
45
|
+
const getPackageManager = () =>
|
|
46
|
+
Match.value(process.env.npm_config_user_agent ?? 'npm').pipe(
|
|
38
47
|
Match.when(String.startsWith('pnpm'), () => 'pnpm'),
|
|
39
48
|
Match.when(String.startsWith('yarn'), () => 'yarn'),
|
|
40
49
|
Match.when(String.startsWith('bun'), () => 'bun'),
|
|
41
50
|
Match.orElse(() => 'npm'),
|
|
42
51
|
);
|
|
52
|
+
|
|
53
|
+
const installPackage = (packageName: string) => {
|
|
54
|
+
const packageManager = getPackageManager();
|
|
43
55
|
return Command.streamLines(
|
|
44
|
-
|
|
56
|
+
MakeCommand(packageManager, 'install', packageName),
|
|
57
|
+
).pipe(Stream.mapEffect(Console.log), Stream.runDrain);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const uninstallPackage = (packageName: string) => {
|
|
61
|
+
const packageManager = getPackageManager();
|
|
62
|
+
const uninstallCmd = packageManager === 'yarn' ? 'remove' : 'uninstall';
|
|
63
|
+
return Command.streamLines(
|
|
64
|
+
MakeCommand(packageManager, uninstallCmd, packageName),
|
|
45
65
|
).pipe(Stream.mapEffect(Console.log), Stream.runDrain);
|
|
46
66
|
};
|
|
47
67
|
|
|
48
68
|
const filterIgnored = (files: readonly SourceFile[]) =>
|
|
49
69
|
Effect.gen(function* () {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
const ignores = yield* Command.string(
|
|
71
|
+
MakeCommand('git', 'check-ignore', '**/*'),
|
|
72
|
+
).pipe(
|
|
73
|
+
Effect.tap(Effect.log),
|
|
74
|
+
Effect.map((_) => _.split('\n')),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
yield* Effect.logDebug(
|
|
78
|
+
'All files in program:',
|
|
79
|
+
files.map((_) => _.fileName),
|
|
80
|
+
);
|
|
81
|
+
yield* Effect.logDebug('Ignored files:', ignores);
|
|
57
82
|
|
|
58
83
|
// Ignore "common files"
|
|
59
|
-
const
|
|
84
|
+
const filteredSourcePaths = files
|
|
60
85
|
.filter(
|
|
61
86
|
(source) =>
|
|
62
|
-
|
|
63
|
-
!source.fileName.includes('packages/')
|
|
87
|
+
source.fileName.startsWith(path.resolve()) && // only look ahead of current directory
|
|
88
|
+
!source.fileName.includes('/trpc/packages/') && // relative paths when running codemod locally
|
|
89
|
+
!ignores.includes(source.fileName), // ignored files
|
|
64
90
|
)
|
|
65
|
-
.map((
|
|
91
|
+
.map((source) => source.fileName);
|
|
92
|
+
|
|
93
|
+
yield* Effect.logDebug('Filtered files:', filteredSourcePaths);
|
|
66
94
|
|
|
67
|
-
|
|
68
|
-
return ignores.filter(relativeFilePaths);
|
|
95
|
+
return filteredSourcePaths;
|
|
69
96
|
});
|
|
70
97
|
|
|
71
|
-
const
|
|
98
|
+
const TSProgram = Effect.succeed(
|
|
72
99
|
findConfigFile(process.cwd(), sys.fileExists),
|
|
73
100
|
).pipe(
|
|
74
101
|
Effect.filterOrFail(Predicate.isNotNullable, () => 'No tsconfig found'),
|
|
@@ -84,73 +111,123 @@ const Program = Effect.succeed(
|
|
|
84
111
|
),
|
|
85
112
|
);
|
|
86
113
|
|
|
114
|
+
// FIXME :: hacky
|
|
87
115
|
const transformPath = (path: string) =>
|
|
88
116
|
process.env.DEV ? path : path.replace('../', './').replace('.ts', '.cjs');
|
|
89
117
|
|
|
90
|
-
const
|
|
91
|
-
'
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
const force = Options.boolean('force').pipe(
|
|
119
|
+
Options.withAlias('f'),
|
|
120
|
+
Options.withDefault(false),
|
|
121
|
+
Options.withDescription('Skip git status check, use with caution'),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* TODO: Instead of default values these should be detected automatically from the TS program
|
|
126
|
+
*/
|
|
127
|
+
const trpcFile = Options.text('trpcFile').pipe(
|
|
128
|
+
Options.withAlias('f'),
|
|
129
|
+
Options.withDefault('~/trpc'),
|
|
130
|
+
Options.withDescription('Path to the trpc import file'),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const trpcImportName = Options.text('trpcImportName').pipe(
|
|
134
|
+
Options.withAlias('i'),
|
|
135
|
+
Options.withDefault('trpc'),
|
|
136
|
+
Options.withDescription('Name of the trpc import'),
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const skipTanstackQuery = Options.boolean('skipTanstackQuery').pipe(
|
|
140
|
+
Options.withAlias('q'),
|
|
141
|
+
Options.withDefault(false),
|
|
142
|
+
Options.withDescription('Skip installing @trpc/tanstack-react-query package'),
|
|
143
|
+
);
|
|
112
144
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
const verbose = Options.boolean('verbose').pipe(
|
|
146
|
+
Options.withAlias('v'),
|
|
147
|
+
Options.withDefault(false),
|
|
148
|
+
Options.withDescription('Enable verbose logging'),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const rootComamnd = CLICommand.make(
|
|
152
|
+
'upgrade',
|
|
153
|
+
{
|
|
154
|
+
force,
|
|
155
|
+
trpcFile,
|
|
156
|
+
trpcImportName,
|
|
157
|
+
skipTanstackQuery,
|
|
158
|
+
verbose,
|
|
159
|
+
},
|
|
160
|
+
(args) =>
|
|
161
|
+
Effect.gen(function* () {
|
|
162
|
+
if (args.verbose) {
|
|
163
|
+
yield* Effect.log('Running upgrade with args:', args);
|
|
164
|
+
}
|
|
165
|
+
if (!args.force) {
|
|
166
|
+
yield* assertCleanGitTree;
|
|
167
|
+
}
|
|
168
|
+
const transforms = yield* pipe(
|
|
169
|
+
Prompt.multiSelect({
|
|
170
|
+
message: 'Select transforms to run',
|
|
171
|
+
choices: [
|
|
172
|
+
{
|
|
173
|
+
title: 'Migrate Hooks to xxxOptions API',
|
|
174
|
+
value: require.resolve(
|
|
175
|
+
transformPath('../transforms/hooksToOptions.ts'),
|
|
176
|
+
),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
title: 'Migrate context provider setup',
|
|
180
|
+
value: require.resolve(
|
|
181
|
+
transformPath('../transforms/provider.ts'),
|
|
182
|
+
),
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
}),
|
|
186
|
+
Effect.flatMap((selected) => {
|
|
187
|
+
if (selected.length === 0) {
|
|
188
|
+
return Effect.fail(
|
|
189
|
+
new Error('Please select at least one transform to run'),
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return Effect.succeed(selected);
|
|
193
|
+
}),
|
|
194
|
+
Effect.map(
|
|
195
|
+
// Make sure provider transform runs first if it's selected
|
|
196
|
+
Array.sortWith((a) => !a.includes('provider.ts'), Order.boolean),
|
|
197
|
+
),
|
|
116
198
|
);
|
|
117
199
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
*/
|
|
121
|
-
const appRouterImportFile = '~/server/routers/_app';
|
|
122
|
-
const appRouterImportName = 'AppRouter';
|
|
123
|
-
const trpcFile = '~/lib/trpc';
|
|
124
|
-
const trpcImportName = 'trpc';
|
|
200
|
+
const program = yield* TSProgram;
|
|
201
|
+
const sourceFiles = program.getSourceFiles();
|
|
125
202
|
|
|
126
203
|
const commitedFiles = yield* filterIgnored(sourceFiles);
|
|
127
|
-
yield* Effect.forEach(
|
|
204
|
+
yield* Effect.forEach(transforms, (transform) => {
|
|
128
205
|
return pipe(
|
|
129
206
|
Effect.log('Running transform', transform),
|
|
130
207
|
Effect.flatMap(() =>
|
|
131
208
|
Effect.tryPromise(async () =>
|
|
132
209
|
import('jscodeshift/src/Runner.js').then(({ run }) =>
|
|
133
|
-
run(transform
|
|
134
|
-
appRouterImportFile,
|
|
135
|
-
appRouterImportName,
|
|
136
|
-
trpcFile,
|
|
137
|
-
trpcImportName,
|
|
138
|
-
}),
|
|
210
|
+
run(transform, commitedFiles, args),
|
|
139
211
|
),
|
|
140
212
|
),
|
|
141
213
|
),
|
|
142
|
-
Effect.map((
|
|
214
|
+
Effect.map((_) => Effect.log('Transform result', _)),
|
|
143
215
|
);
|
|
144
216
|
});
|
|
145
217
|
|
|
146
|
-
|
|
147
|
-
|
|
218
|
+
if (!args.skipTanstackQuery) {
|
|
219
|
+
yield* Effect.log('Installing @trpc/tanstack-react-query');
|
|
220
|
+
yield* installPackage('@trpc/tanstack-react-query');
|
|
148
221
|
|
|
149
|
-
|
|
150
|
-
|
|
222
|
+
yield* Effect.log('Uninstalling @trpc/react-query');
|
|
223
|
+
yield* uninstallPackage('@trpc/react-query');
|
|
224
|
+
}
|
|
225
|
+
}).pipe(
|
|
226
|
+
Logger.withMinimumLogLevel(args.verbose ? LogLevel.Debug : LogLevel.Info),
|
|
227
|
+
),
|
|
151
228
|
);
|
|
152
229
|
|
|
153
|
-
const cli = CLICommand.run(
|
|
230
|
+
const cli = CLICommand.run(rootComamnd, {
|
|
154
231
|
name: 'tRPC Upgrade CLI',
|
|
155
232
|
version: `v${version}`,
|
|
156
233
|
});
|
|
@@ -13,7 +13,6 @@ import type {
|
|
|
13
13
|
} from 'jscodeshift';
|
|
14
14
|
|
|
15
15
|
interface TransformOptions extends Options {
|
|
16
|
-
trpcFile?: string;
|
|
17
16
|
trpcImportName?: string;
|
|
18
17
|
}
|
|
19
18
|
|
|
@@ -61,9 +60,9 @@ export default function transform(
|
|
|
61
60
|
api: API,
|
|
62
61
|
options: TransformOptions,
|
|
63
62
|
) {
|
|
64
|
-
const {
|
|
65
|
-
if (!
|
|
66
|
-
throw new Error('
|
|
63
|
+
const { trpcImportName } = options;
|
|
64
|
+
if (!trpcImportName) {
|
|
65
|
+
throw new Error('trpcImportName is required');
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
const j = api.jscodeshift;
|
|
@@ -72,44 +71,27 @@ export default function transform(
|
|
|
72
71
|
|
|
73
72
|
// Traverse all functions, and _do stuff_
|
|
74
73
|
root.find(j.FunctionDeclaration).forEach((path) => {
|
|
75
|
-
if (j(path).find(j.Identifier, { name: trpcImportName }).size() > 0) {
|
|
76
|
-
updateTRPCImport(path);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
74
|
replaceHooksWithOptions(path);
|
|
80
75
|
removeSuspenseDestructuring(path);
|
|
81
76
|
migrateUseUtils(path);
|
|
82
77
|
});
|
|
83
78
|
root.find(j.ArrowFunctionExpression).forEach((path) => {
|
|
84
|
-
if (j(path).find(j.Identifier, { name: trpcImportName }).size() > 0) {
|
|
85
|
-
updateTRPCImport(path);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
79
|
replaceHooksWithOptions(path);
|
|
89
80
|
removeSuspenseDestructuring(path);
|
|
90
81
|
migrateUseUtils(path);
|
|
91
82
|
});
|
|
92
83
|
|
|
84
|
+
if (dirtyFlag) {
|
|
85
|
+
updateTRPCImport();
|
|
86
|
+
}
|
|
87
|
+
|
|
93
88
|
/**
|
|
94
89
|
* === HELPER FUNCTIONS BELOW ===
|
|
95
90
|
*/
|
|
96
91
|
|
|
97
|
-
function
|
|
92
|
+
function ensureUseTRPCCall(
|
|
98
93
|
path: ASTPath<FunctionDeclaration | ArrowFunctionExpression>,
|
|
99
94
|
) {
|
|
100
|
-
const specifier = root
|
|
101
|
-
.find(j.ImportDeclaration, {
|
|
102
|
-
source: { value: trpcFile },
|
|
103
|
-
})
|
|
104
|
-
.find(j.ImportSpecifier, { imported: { name: trpcImportName } });
|
|
105
|
-
|
|
106
|
-
if (specifier.size() === 0) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
specifier.replaceWith(j.importSpecifier(j.identifier('useTRPC')));
|
|
111
|
-
dirtyFlag = true;
|
|
112
|
-
|
|
113
95
|
const variableDeclaration = j.variableDeclaration('const', [
|
|
114
96
|
j.variableDeclarator(
|
|
115
97
|
j.identifier(trpcImportName!),
|
|
@@ -118,10 +100,21 @@ export default function transform(
|
|
|
118
100
|
]);
|
|
119
101
|
|
|
120
102
|
if (j.FunctionDeclaration.check(path.node)) {
|
|
121
|
-
|
|
122
|
-
|
|
103
|
+
path.node.body.body.unshift(variableDeclaration);
|
|
104
|
+
dirtyFlag = true;
|
|
123
105
|
} else if (j.BlockStatement.check(path.node.body)) {
|
|
124
106
|
path.node.body.body.unshift(variableDeclaration);
|
|
107
|
+
dirtyFlag = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function updateTRPCImport() {
|
|
112
|
+
const specifier = root.find(j.ImportSpecifier, {
|
|
113
|
+
imported: { name: trpcImportName },
|
|
114
|
+
});
|
|
115
|
+
if (specifier.size() > 0) {
|
|
116
|
+
specifier.replaceWith(j.importSpecifier(j.identifier('useTRPC')));
|
|
117
|
+
dirtyFlag = true;
|
|
125
118
|
}
|
|
126
119
|
}
|
|
127
120
|
|
|
@@ -148,11 +141,12 @@ export default function transform(
|
|
|
148
141
|
}
|
|
149
142
|
|
|
150
143
|
function replaceHooksWithOptions(
|
|
151
|
-
|
|
144
|
+
fnPath: ASTPath<FunctionDeclaration | ArrowFunctionExpression>,
|
|
152
145
|
) {
|
|
153
146
|
// REplace proxy-hooks with useX(options())
|
|
147
|
+
let hasInserted = false;
|
|
154
148
|
for (const [hook, { fn, lib }] of Object.entries(hookToOptions)) {
|
|
155
|
-
j(
|
|
149
|
+
j(fnPath)
|
|
156
150
|
.find(j.CallExpression, {
|
|
157
151
|
callee: {
|
|
158
152
|
property: { name: hook },
|
|
@@ -171,6 +165,11 @@ export default function transform(
|
|
|
171
165
|
// Rename the hook to the options function
|
|
172
166
|
memberExpr.property.name = fn;
|
|
173
167
|
|
|
168
|
+
if (!hasInserted) {
|
|
169
|
+
ensureUseTRPCCall(fnPath);
|
|
170
|
+
hasInserted = true;
|
|
171
|
+
}
|
|
172
|
+
|
|
174
173
|
// Wrap it in the hook call
|
|
175
174
|
j(path).replaceWith(
|
|
176
175
|
j.callExpression(j.identifier(hook), [path.node]),
|
|
@@ -237,7 +236,7 @@ export default function transform(
|
|
|
237
236
|
|
|
238
237
|
// Replace util.PATH.proxyMethod() with trpc.PATH.queryFilter()
|
|
239
238
|
const proxyMethod = memberExpr.property.name as ProxyMethod;
|
|
240
|
-
memberExpr.object.object = j.identifier(
|
|
239
|
+
memberExpr.object.object = j.identifier(trpcImportName!);
|
|
241
240
|
memberExpr.property = j.identifier('queryFilter');
|
|
242
241
|
|
|
243
242
|
// Wrap it in queryClient.utilMethod()
|
|
@@ -285,8 +284,6 @@ export default function transform(
|
|
|
285
284
|
return;
|
|
286
285
|
}
|
|
287
286
|
|
|
288
|
-
console.log(declarator.init.callee.name);
|
|
289
|
-
|
|
290
287
|
const tuple = j.ArrayPattern.check(declarator?.id)
|
|
291
288
|
? declarator.id
|
|
292
289
|
: null;
|
|
@@ -297,7 +294,7 @@ export default function transform(
|
|
|
297
294
|
? tuple.elements[1].name
|
|
298
295
|
: null;
|
|
299
296
|
|
|
300
|
-
if (
|
|
297
|
+
if (queryName) {
|
|
301
298
|
declarator.id = j.identifier(queryName);
|
|
302
299
|
dirtyFlag = true;
|
|
303
300
|
|
|
@@ -311,6 +308,12 @@ export default function transform(
|
|
|
311
308
|
]),
|
|
312
309
|
);
|
|
313
310
|
}
|
|
311
|
+
} else if (dataName) {
|
|
312
|
+
// const [dataName] = ... => const { data: dataName } = ...
|
|
313
|
+
declarator.id = j.objectPattern([
|
|
314
|
+
j.property('init', j.identifier('data'), j.identifier(dataName)),
|
|
315
|
+
]);
|
|
316
|
+
dirtyFlag = true;
|
|
314
317
|
}
|
|
315
318
|
});
|
|
316
319
|
}
|
|
@@ -319,5 +322,3 @@ export default function transform(
|
|
|
319
322
|
}
|
|
320
323
|
|
|
321
324
|
export const parser = 'tsx';
|
|
322
|
-
|
|
323
|
-
// https://go.codemod.com/ddX54TM
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { API, FileInfo, Options } from 'jscodeshift';
|
|
2
2
|
|
|
3
3
|
interface TransformOptions extends Options {
|
|
4
|
-
trpcFile?: string;
|
|
5
4
|
trpcImportName?: string;
|
|
6
5
|
}
|
|
7
6
|
|
|
@@ -10,32 +9,13 @@ export default function transform(
|
|
|
10
9
|
api: API,
|
|
11
10
|
options: TransformOptions,
|
|
12
11
|
) {
|
|
13
|
-
const {
|
|
14
|
-
|
|
12
|
+
const { trpcImportName } = options;
|
|
13
|
+
let routerName: string | undefined = undefined;
|
|
15
14
|
|
|
16
15
|
const j = api.jscodeshift;
|
|
17
16
|
const root = j(file.source);
|
|
18
17
|
let dirtyFlag = false;
|
|
19
18
|
|
|
20
|
-
function upsertAppRouterImport() {
|
|
21
|
-
if (
|
|
22
|
-
root
|
|
23
|
-
.find(j.ImportDeclaration, { source: { value: appRouterImportFile } })
|
|
24
|
-
.size() === 0
|
|
25
|
-
) {
|
|
26
|
-
root
|
|
27
|
-
.find(j.ImportDeclaration)
|
|
28
|
-
.at(-1)
|
|
29
|
-
.insertAfter(
|
|
30
|
-
j.importDeclaration(
|
|
31
|
-
[j.importSpecifier(j.identifier(appRouterImportName))],
|
|
32
|
-
j.literal(appRouterImportFile),
|
|
33
|
-
'type',
|
|
34
|
-
),
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
19
|
// Find the variable declaration for `trpc`
|
|
40
20
|
root.find(j.VariableDeclaration).forEach((path) => {
|
|
41
21
|
const declaration = path.node.declarations[0];
|
|
@@ -48,6 +28,11 @@ export default function transform(
|
|
|
48
28
|
j.Identifier.check(declaration.init.callee) &&
|
|
49
29
|
declaration.init.callee.name === 'createTRPCReact'
|
|
50
30
|
) {
|
|
31
|
+
// Get router name ( TODO : should probably get this from the TS compiler along with the import path)
|
|
32
|
+
routerName =
|
|
33
|
+
declaration.init.original?.typeParameters?.params?.[0]?.typeName
|
|
34
|
+
?.name;
|
|
35
|
+
|
|
51
36
|
// Replace the `createTRPCReact` call with `createTRPCContext`
|
|
52
37
|
declaration.init.callee.name = 'createTRPCContext';
|
|
53
38
|
|
|
@@ -89,7 +74,7 @@ export default function transform(
|
|
|
89
74
|
});
|
|
90
75
|
}
|
|
91
76
|
|
|
92
|
-
// Replace trpc.createClient with createTRPCClient
|
|
77
|
+
// Replace trpc.createClient with createTRPCClient<TRouter>
|
|
93
78
|
root
|
|
94
79
|
.find(j.CallExpression, {
|
|
95
80
|
callee: {
|
|
@@ -99,12 +84,13 @@ export default function transform(
|
|
|
99
84
|
})
|
|
100
85
|
.forEach((path) => {
|
|
101
86
|
path.node.callee = j.identifier('createTRPCClient');
|
|
102
|
-
// Add the type parameter `<AppRouter>`
|
|
103
|
-
path.node.typeParameters = j.tsTypeParameterInstantiation([
|
|
104
|
-
j.tsTypeReference(j.identifier(appRouterImportName)),
|
|
105
|
-
]);
|
|
106
|
-
upsertAppRouterImport();
|
|
107
87
|
dirtyFlag = true;
|
|
88
|
+
|
|
89
|
+
if (routerName) {
|
|
90
|
+
(path.node as any).typeParameters = j.tsTypeParameterInstantiation([
|
|
91
|
+
j.tsTypeReference(j.identifier(routerName)),
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
108
94
|
});
|
|
109
95
|
|
|
110
96
|
// Replace <trpc.Provider client={...} with <TRPCProvider trpcClient={...}
|
|
@@ -146,13 +132,11 @@ export default function transform(
|
|
|
146
132
|
|
|
147
133
|
// Replace trpc import with TRPCProvider
|
|
148
134
|
root
|
|
149
|
-
.find(j.
|
|
150
|
-
|
|
135
|
+
.find(j.ImportSpecifier, {
|
|
136
|
+
imported: { name: trpcImportName },
|
|
151
137
|
})
|
|
152
138
|
.forEach((path) => {
|
|
153
|
-
path.node.
|
|
154
|
-
j.importSpecifier(j.identifier('TRPCProvider')),
|
|
155
|
-
];
|
|
139
|
+
path.node.name = j.identifier('TRPCProvider');
|
|
156
140
|
});
|
|
157
141
|
}
|
|
158
142
|
|