@trpc/upgrade 0.0.0-alpha.30 → 0.0.0-alpha.31
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/dist/bin.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parse } from '@bomb.sh/args';
|
|
3
|
+
import * as p from '@clack/prompts';
|
|
4
|
+
import { intro, log, multiselect, isCancel, outro } from '@clack/prompts';
|
|
5
|
+
import * as ts from 'typescript';
|
|
6
|
+
import * as Path from 'path';
|
|
7
|
+
import * as CP from 'node:child_process';
|
|
8
|
+
import * as Util from 'node:util';
|
|
9
|
+
import __node_cjsModule from 'node:module';
|
|
10
|
+
|
|
11
|
+
var version = "0.0.0-alpha.30";
|
|
12
|
+
|
|
13
|
+
function getProgram(args) {
|
|
14
|
+
const configFile = ts.findConfigFile(process.cwd(), (filepath)=>ts.sys.fileExists(filepath));
|
|
15
|
+
if (!configFile) {
|
|
16
|
+
p.log.error('No tsconfig found');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
if (args.verbose) {
|
|
20
|
+
p.log.info(`Using tsconfig: ${configFile}`);
|
|
21
|
+
}
|
|
22
|
+
const { config } = ts.readConfigFile(configFile, (filepath)=>ts.sys.readFile(filepath));
|
|
23
|
+
const parsedConfig = ts.parseJsonConfigFileContent(config, ts.sys, process.cwd());
|
|
24
|
+
const program = ts.createProgram({
|
|
25
|
+
options: parsedConfig.options,
|
|
26
|
+
rootNames: parsedConfig.fileNames,
|
|
27
|
+
configFileParsingDiagnostics: parsedConfig.errors
|
|
28
|
+
});
|
|
29
|
+
return program;
|
|
30
|
+
}
|
|
31
|
+
function findSourceAndImportName(program) {
|
|
32
|
+
const files = program.getSourceFiles().filter((sourceFile)=>{
|
|
33
|
+
if (sourceFile.isDeclarationFile) return false;
|
|
34
|
+
let found = false;
|
|
35
|
+
ts.forEachChild(sourceFile, (node)=>{
|
|
36
|
+
if (!found && ts.isImportDeclaration(node)) {
|
|
37
|
+
const { moduleSpecifier } = node;
|
|
38
|
+
if (ts.isStringLiteral(moduleSpecifier) && moduleSpecifier.text.includes('@trpc/react-query')) {
|
|
39
|
+
found = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return found;
|
|
44
|
+
});
|
|
45
|
+
let importName = 'trpc';
|
|
46
|
+
files.forEach((sourceFile)=>{
|
|
47
|
+
ts.forEachChild(sourceFile, (node)=>{
|
|
48
|
+
if (ts.isVariableStatement(node) && node.modifiers?.some((mod)=>mod.getText(sourceFile) === 'export')) {
|
|
49
|
+
node.declarationList.declarations.forEach((declaration)=>{
|
|
50
|
+
if (ts.isVariableDeclaration(declaration) && declaration.initializer && ts.isCallExpression(declaration.initializer) && ts.isIdentifier(declaration.initializer.expression) && declaration.initializer.expression.getText(sourceFile) === 'createTRPCReact') {
|
|
51
|
+
importName = declaration.name.getText(sourceFile);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
files: files.map((d)=>d.fileName),
|
|
59
|
+
importName
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function findTRPCImportReferences(program) {
|
|
63
|
+
const { files: filesImportingTRPC, importName } = findSourceAndImportName(program);
|
|
64
|
+
const trpcReferenceSpecifiers = new Map();
|
|
65
|
+
program.getSourceFiles().forEach((sourceFile)=>{
|
|
66
|
+
if (sourceFile.isDeclarationFile) return;
|
|
67
|
+
ts.forEachChild(sourceFile, (node)=>{
|
|
68
|
+
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
69
|
+
const resolved = ts.resolveModuleName(node.moduleSpecifier.text, sourceFile.fileName, program.getCompilerOptions(), ts.sys);
|
|
70
|
+
if (resolved.resolvedModule && filesImportingTRPC.includes(resolved.resolvedModule.resolvedFileName)) {
|
|
71
|
+
trpcReferenceSpecifiers.set(resolved.resolvedModule.resolvedFileName, node.moduleSpecifier.text);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
const counts = {};
|
|
77
|
+
let currentMax = 0;
|
|
78
|
+
const mostUsed = {
|
|
79
|
+
file: ''
|
|
80
|
+
};
|
|
81
|
+
[
|
|
82
|
+
...trpcReferenceSpecifiers.values()
|
|
83
|
+
].forEach((specifier)=>{
|
|
84
|
+
counts[specifier] = (counts[specifier] || 0) + 1;
|
|
85
|
+
if (counts[specifier] > currentMax) {
|
|
86
|
+
currentMax = counts[specifier];
|
|
87
|
+
mostUsed.file = specifier;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
importName,
|
|
92
|
+
mostUsed,
|
|
93
|
+
all: Object.fromEntries(trpcReferenceSpecifiers.entries())
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const execa = Util.promisify(CP.exec);
|
|
98
|
+
|
|
99
|
+
async function assertCleanGitTree() {
|
|
100
|
+
const { stdout } = await execa('git status');
|
|
101
|
+
if (!stdout.includes('nothing to commit')) {
|
|
102
|
+
p.cancel('Git tree is not clean, please commit your changes and try again, or run with `--force`');
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function filterIgnored(files) {
|
|
107
|
+
const { stdout } = await execa('git check-ignore **/*');
|
|
108
|
+
const ignores = stdout.split('\n');
|
|
109
|
+
if (process.env.VERBOSE) {
|
|
110
|
+
p.log.info(`cwd: ${process.cwd()}`);
|
|
111
|
+
p.log.info(`All files in program: ${files.map((file)=>file.fileName).join(', ')}`);
|
|
112
|
+
p.log.info(`Ignored files: ${ignores.join(', ')}`);
|
|
113
|
+
}
|
|
114
|
+
// Ignore "common files"
|
|
115
|
+
const filteredSourcePaths = files.filter((source)=>source.fileName.startsWith(Path.resolve()) && // only look ahead of current directory
|
|
116
|
+
!source.fileName.includes('/trpc/packages/') && // relative paths when running codemod locally
|
|
117
|
+
!source.fileName.includes('/node_modules/') && // always ignore node_modules
|
|
118
|
+
!ignores.includes(source.fileName)).map((source)=>source.fileName);
|
|
119
|
+
if (process.env.VERBOSE) {
|
|
120
|
+
p.log.info(`Filtered files: ${filteredSourcePaths.join(', ')}`);
|
|
121
|
+
}
|
|
122
|
+
return filteredSourcePaths;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getPackageManager() {
|
|
126
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
127
|
+
if (userAgent?.startsWith('pnpm')) return 'pnpm';
|
|
128
|
+
if (userAgent?.startsWith('yarn')) return 'yarn';
|
|
129
|
+
if (userAgent?.startsWith('bun')) return 'bun';
|
|
130
|
+
return 'npm';
|
|
131
|
+
}
|
|
132
|
+
async function installPackage(packageName) {
|
|
133
|
+
const packageManager = getPackageManager();
|
|
134
|
+
const installCmd = packageManager === 'yarn' ? 'add' : 'install';
|
|
135
|
+
const { stdout, stderr } = await execa(`${packageManager} ${installCmd} ${packageName}`);
|
|
136
|
+
if (stderr) {
|
|
137
|
+
p.log.error(stderr);
|
|
138
|
+
}
|
|
139
|
+
p.log.info(stdout);
|
|
140
|
+
}
|
|
141
|
+
async function uninstallPackage(packageName) {
|
|
142
|
+
const packageManager = getPackageManager();
|
|
143
|
+
const uninstallCmd = packageManager === 'yarn' ? 'remove' : 'uninstall';
|
|
144
|
+
const { stdout, stderr } = await execa(`${packageManager} ${uninstallCmd} ${packageName}`);
|
|
145
|
+
if (stderr) {
|
|
146
|
+
p.log.error(stderr);
|
|
147
|
+
}
|
|
148
|
+
p.log.info(stdout);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const require = __node_cjsModule.createRequire(import.meta.url);
|
|
152
|
+
|
|
153
|
+
const args = parse(process.argv.slice(2), {
|
|
154
|
+
default: {
|
|
155
|
+
force: false,
|
|
156
|
+
skipTanstackQuery: false,
|
|
157
|
+
verbose: false
|
|
158
|
+
},
|
|
159
|
+
alias: {
|
|
160
|
+
f: 'force',
|
|
161
|
+
h: 'help',
|
|
162
|
+
v: 'verbose',
|
|
163
|
+
q: 'skipTanstackQuery'
|
|
164
|
+
},
|
|
165
|
+
boolean: true
|
|
166
|
+
});
|
|
167
|
+
intro(`tRPC Upgrade CLI v${version}`);
|
|
168
|
+
if (args.help) {
|
|
169
|
+
log.info(`
|
|
170
|
+
Usage: upgrade [options]
|
|
171
|
+
|
|
172
|
+
Options:
|
|
173
|
+
-f, --force Skip git status check, use with caution
|
|
174
|
+
-q, --skipTanstackQuery Skip installing @trpc/tanstack-react-query package
|
|
175
|
+
-v, --verbose Enable verbose logging
|
|
176
|
+
-h, --help Show help
|
|
177
|
+
`.trim());
|
|
178
|
+
process.exit(0);
|
|
179
|
+
}
|
|
180
|
+
if (args.verbose) {
|
|
181
|
+
log.info(`Running upgrade with args: ${JSON.stringify(args, null, 2)}`);
|
|
182
|
+
}
|
|
183
|
+
if (!args.force) {
|
|
184
|
+
await assertCleanGitTree();
|
|
185
|
+
}
|
|
186
|
+
const transforms = await multiselect({
|
|
187
|
+
message: 'Select transforms to run',
|
|
188
|
+
options: [
|
|
189
|
+
{
|
|
190
|
+
value: require.resolve('@trpc/upgrade/transforms/hooksToOptions'),
|
|
191
|
+
label: 'Migrate Hooks to xxxOptions API'
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
value: require.resolve('@trpc/upgrade/transforms/provider'),
|
|
195
|
+
label: 'Migrate context provider setup'
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
});
|
|
199
|
+
if (isCancel(transforms)) process.exit(0);
|
|
200
|
+
// Make sure provider transform runs first if it's selected
|
|
201
|
+
const sortedTransforms = transforms.sort((a)=>a.includes('provider') ? -1 : 1);
|
|
202
|
+
const program = getProgram(args);
|
|
203
|
+
const sourceFiles = program.getSourceFiles();
|
|
204
|
+
const possibleReferences = findTRPCImportReferences(program);
|
|
205
|
+
const trpcFile = possibleReferences.mostUsed.file;
|
|
206
|
+
const trpcImportName = possibleReferences.importName;
|
|
207
|
+
const commitedFiles = await filterIgnored(sourceFiles);
|
|
208
|
+
for (const transform of sortedTransforms){
|
|
209
|
+
log.info(`Running transform: ${transform}`);
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
211
|
+
const { run } = require('jscodeshift/src/Runner.js');
|
|
212
|
+
await run(transform, commitedFiles, {
|
|
213
|
+
...args,
|
|
214
|
+
trpcFile,
|
|
215
|
+
trpcImportName
|
|
216
|
+
});
|
|
217
|
+
log.info(`Transform ${transform} completed`);
|
|
218
|
+
}
|
|
219
|
+
if (!args.skipTanstackQuery) {
|
|
220
|
+
log.info('Installing @trpc/tanstack-react-query');
|
|
221
|
+
await installPackage('@trpc/tanstack-react-query');
|
|
222
|
+
log.success('@trpc/tanstack-react-query installed');
|
|
223
|
+
log.info('Uninstalling @trpc/react-query');
|
|
224
|
+
await uninstallPackage('@trpc/react-query');
|
|
225
|
+
log.success('@trpc/react-query uninstalled');
|
|
226
|
+
}
|
|
227
|
+
outro('Upgrade complete! 🎉');
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Replaces the identifier for the root path key
|
|
5
3
|
* of a member expression
|
|
@@ -261,5 +259,4 @@ function transform(file, api, options) {
|
|
|
261
259
|
}
|
|
262
260
|
const parser = 'tsx';
|
|
263
261
|
|
|
264
|
-
|
|
265
|
-
exports.parser = parser;
|
|
262
|
+
export { transform as default, parser };
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
-
|
|
3
1
|
function transform(file, api, options) {
|
|
4
2
|
const { trpcImportName } = options;
|
|
5
3
|
let routerName = undefined;
|
|
@@ -116,5 +114,4 @@ function transform(file, api, options) {
|
|
|
116
114
|
}
|
|
117
115
|
const parser = 'tsx';
|
|
118
116
|
|
|
119
|
-
|
|
120
|
-
exports.parser = parser;
|
|
117
|
+
export { transform as default, parser };
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trpc/upgrade",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.31",
|
|
4
4
|
"description": "Upgrade scripts for tRPC",
|
|
5
5
|
"author": "juliusmarminge",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": "./dist/bin.js",
|
|
8
9
|
"homepage": "https://trpc.io",
|
|
9
10
|
"repository": {
|
|
10
11
|
"type": "git",
|
|
@@ -13,10 +14,10 @@
|
|
|
13
14
|
},
|
|
14
15
|
"exports": {
|
|
15
16
|
"./transforms/hooksToOptions": {
|
|
16
|
-
"default": "./dist/transforms/hooksToOptions.
|
|
17
|
+
"default": "./dist/transforms/hooksToOptions.js"
|
|
17
18
|
},
|
|
18
19
|
"./transforms/provider": {
|
|
19
|
-
"default": "./dist/transforms/provider.
|
|
20
|
+
"default": "./dist/transforms/provider.js"
|
|
20
21
|
}
|
|
21
22
|
},
|
|
22
23
|
"files": [
|
package/src/bin/index.ts
CHANGED
|
@@ -6,27 +6,26 @@ import { findTRPCImportReferences, getProgram } from '../lib/ast/scanners';
|
|
|
6
6
|
import { assertCleanGitTree, filterIgnored } from '../lib/git';
|
|
7
7
|
import { installPackage, uninstallPackage } from '../lib/pkgmgr';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
});
|
|
9
|
+
const args = parse(process.argv.slice(2), {
|
|
10
|
+
default: {
|
|
11
|
+
force: false,
|
|
12
|
+
skipTanstackQuery: false,
|
|
13
|
+
verbose: false,
|
|
14
|
+
},
|
|
15
|
+
alias: {
|
|
16
|
+
f: 'force',
|
|
17
|
+
h: 'help',
|
|
18
|
+
v: 'verbose',
|
|
19
|
+
q: 'skipTanstackQuery',
|
|
20
|
+
},
|
|
21
|
+
boolean: true,
|
|
22
|
+
});
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
intro(`tRPC Upgrade CLI v${version}`);
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
if (args.help) {
|
|
27
|
+
log.info(
|
|
28
|
+
`
|
|
30
29
|
Usage: upgrade [options]
|
|
31
30
|
|
|
32
31
|
Options:
|
|
@@ -35,66 +34,66 @@ Options:
|
|
|
35
34
|
-v, --verbose Enable verbose logging
|
|
36
35
|
-h, --help Show help
|
|
37
36
|
`.trim(),
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
);
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
if (args.verbose) {
|
|
42
|
+
log.info(`Running upgrade with args: ${JSON.stringify(args, null, 2)}`);
|
|
43
|
+
}
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
if (!args.force) {
|
|
46
|
+
await assertCleanGitTree();
|
|
47
|
+
}
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
49
|
+
const transforms = await multiselect({
|
|
50
|
+
message: 'Select transforms to run',
|
|
51
|
+
options: [
|
|
52
|
+
{
|
|
53
|
+
value: require.resolve('@trpc/upgrade/transforms/hooksToOptions'),
|
|
54
|
+
label: 'Migrate Hooks to xxxOptions API',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
value: require.resolve('@trpc/upgrade/transforms/provider'),
|
|
58
|
+
label: 'Migrate context provider setup',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
if (isCancel(transforms)) process.exit(0);
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
// Make sure provider transform runs first if it's selected
|
|
65
|
+
const sortedTransforms = transforms.sort((a) =>
|
|
66
|
+
a.includes('provider') ? -1 : 1,
|
|
67
|
+
);
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
const program = getProgram(args);
|
|
70
|
+
const sourceFiles = program.getSourceFiles();
|
|
71
|
+
const possibleReferences = findTRPCImportReferences(program);
|
|
72
|
+
const trpcFile = possibleReferences.mostUsed.file;
|
|
73
|
+
const trpcImportName = possibleReferences.importName;
|
|
75
74
|
|
|
76
|
-
|
|
75
|
+
const commitedFiles = await filterIgnored(sourceFiles);
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
77
|
+
for (const transform of sortedTransforms) {
|
|
78
|
+
log.info(`Running transform: ${transform}`);
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
80
|
+
const { run } = require('jscodeshift/src/Runner.js');
|
|
81
|
+
await run(transform, commitedFiles, {
|
|
82
|
+
...args,
|
|
83
|
+
trpcFile,
|
|
84
|
+
trpcImportName,
|
|
85
|
+
});
|
|
86
|
+
log.info(`Transform ${transform} completed`);
|
|
87
|
+
}
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
if (!args.skipTanstackQuery) {
|
|
90
|
+
log.info('Installing @trpc/tanstack-react-query');
|
|
91
|
+
await installPackage('@trpc/tanstack-react-query');
|
|
92
|
+
log.success('@trpc/tanstack-react-query installed');
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
log.info('Uninstalling @trpc/react-query');
|
|
95
|
+
await uninstallPackage('@trpc/react-query');
|
|
96
|
+
log.success('@trpc/react-query uninstalled');
|
|
97
|
+
}
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
})();
|
|
99
|
+
outro('Upgrade complete! 🎉');
|
package/dist/bin.cjs
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
var args = require('@bomb.sh/args');
|
|
3
|
-
var p = require('@clack/prompts');
|
|
4
|
-
var ts = require('typescript');
|
|
5
|
-
var Path = require('path');
|
|
6
|
-
var CP = require('node:child_process');
|
|
7
|
-
var Util = require('node:util');
|
|
8
|
-
|
|
9
|
-
function _interopNamespace(e) {
|
|
10
|
-
if (e && e.__esModule) return e;
|
|
11
|
-
var n = Object.create(null);
|
|
12
|
-
if (e) {
|
|
13
|
-
Object.keys(e).forEach(function (k) {
|
|
14
|
-
if (k !== 'default') {
|
|
15
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
-
enumerable: true,
|
|
18
|
-
get: function () { return e[k]; }
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
n.default = e;
|
|
24
|
-
return n;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
var p__namespace = /*#__PURE__*/_interopNamespace(p);
|
|
28
|
-
var ts__namespace = /*#__PURE__*/_interopNamespace(ts);
|
|
29
|
-
var Path__namespace = /*#__PURE__*/_interopNamespace(Path);
|
|
30
|
-
var CP__namespace = /*#__PURE__*/_interopNamespace(CP);
|
|
31
|
-
var Util__namespace = /*#__PURE__*/_interopNamespace(Util);
|
|
32
|
-
|
|
33
|
-
var version = "0.0.0-alpha.29";
|
|
34
|
-
|
|
35
|
-
function getProgram(args) {
|
|
36
|
-
const configFile = ts__namespace.findConfigFile(process.cwd(), (filepath)=>ts__namespace.sys.fileExists(filepath));
|
|
37
|
-
if (!configFile) {
|
|
38
|
-
p__namespace.log.error('No tsconfig found');
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
if (args.verbose) {
|
|
42
|
-
p__namespace.log.info(`Using tsconfig: ${configFile}`);
|
|
43
|
-
}
|
|
44
|
-
const { config } = ts__namespace.readConfigFile(configFile, (filepath)=>ts__namespace.sys.readFile(filepath));
|
|
45
|
-
const parsedConfig = ts__namespace.parseJsonConfigFileContent(config, ts__namespace.sys, process.cwd());
|
|
46
|
-
const program = ts__namespace.createProgram({
|
|
47
|
-
options: parsedConfig.options,
|
|
48
|
-
rootNames: parsedConfig.fileNames,
|
|
49
|
-
configFileParsingDiagnostics: parsedConfig.errors
|
|
50
|
-
});
|
|
51
|
-
return program;
|
|
52
|
-
}
|
|
53
|
-
function findSourceAndImportName(program) {
|
|
54
|
-
const files = program.getSourceFiles().filter((sourceFile)=>{
|
|
55
|
-
if (sourceFile.isDeclarationFile) return false;
|
|
56
|
-
let found = false;
|
|
57
|
-
ts__namespace.forEachChild(sourceFile, (node)=>{
|
|
58
|
-
if (!found && ts__namespace.isImportDeclaration(node)) {
|
|
59
|
-
const { moduleSpecifier } = node;
|
|
60
|
-
if (ts__namespace.isStringLiteral(moduleSpecifier) && moduleSpecifier.text.includes('@trpc/react-query')) {
|
|
61
|
-
found = true;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
return found;
|
|
66
|
-
});
|
|
67
|
-
let importName = 'trpc';
|
|
68
|
-
files.forEach((sourceFile)=>{
|
|
69
|
-
ts__namespace.forEachChild(sourceFile, (node)=>{
|
|
70
|
-
if (ts__namespace.isVariableStatement(node) && node.modifiers?.some((mod)=>mod.getText(sourceFile) === 'export')) {
|
|
71
|
-
node.declarationList.declarations.forEach((declaration)=>{
|
|
72
|
-
if (ts__namespace.isVariableDeclaration(declaration) && declaration.initializer && ts__namespace.isCallExpression(declaration.initializer) && ts__namespace.isIdentifier(declaration.initializer.expression) && declaration.initializer.expression.getText(sourceFile) === 'createTRPCReact') {
|
|
73
|
-
importName = declaration.name.getText(sourceFile);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
return {
|
|
80
|
-
files: files.map((d)=>d.fileName),
|
|
81
|
-
importName
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function findTRPCImportReferences(program) {
|
|
85
|
-
const { files: filesImportingTRPC, importName } = findSourceAndImportName(program);
|
|
86
|
-
const trpcReferenceSpecifiers = new Map();
|
|
87
|
-
program.getSourceFiles().forEach((sourceFile)=>{
|
|
88
|
-
if (sourceFile.isDeclarationFile) return;
|
|
89
|
-
ts__namespace.forEachChild(sourceFile, (node)=>{
|
|
90
|
-
if (ts__namespace.isImportDeclaration(node) && ts__namespace.isStringLiteral(node.moduleSpecifier)) {
|
|
91
|
-
const resolved = ts__namespace.resolveModuleName(node.moduleSpecifier.text, sourceFile.fileName, program.getCompilerOptions(), ts__namespace.sys);
|
|
92
|
-
if (resolved.resolvedModule && filesImportingTRPC.includes(resolved.resolvedModule.resolvedFileName)) {
|
|
93
|
-
trpcReferenceSpecifiers.set(resolved.resolvedModule.resolvedFileName, node.moduleSpecifier.text);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
const counts = {};
|
|
99
|
-
let currentMax = 0;
|
|
100
|
-
const mostUsed = {
|
|
101
|
-
file: ''
|
|
102
|
-
};
|
|
103
|
-
[
|
|
104
|
-
...trpcReferenceSpecifiers.values()
|
|
105
|
-
].forEach((specifier)=>{
|
|
106
|
-
counts[specifier] = (counts[specifier] || 0) + 1;
|
|
107
|
-
if (counts[specifier] > currentMax) {
|
|
108
|
-
currentMax = counts[specifier];
|
|
109
|
-
mostUsed.file = specifier;
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
return {
|
|
113
|
-
importName,
|
|
114
|
-
mostUsed,
|
|
115
|
-
all: Object.fromEntries(trpcReferenceSpecifiers.entries())
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const execa = Util__namespace.promisify(CP__namespace.exec);
|
|
120
|
-
|
|
121
|
-
async function assertCleanGitTree() {
|
|
122
|
-
const { stdout } = await execa('git status');
|
|
123
|
-
if (!stdout.includes('nothing to commit')) {
|
|
124
|
-
p__namespace.cancel('Git tree is not clean, please commit your changes and try again, or run with `--force`');
|
|
125
|
-
process.exit(1);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
async function filterIgnored(files) {
|
|
129
|
-
const { stdout } = await execa('git check-ignore **/*');
|
|
130
|
-
const ignores = stdout.split('\n');
|
|
131
|
-
if (process.env.VERBOSE) {
|
|
132
|
-
p__namespace.log.info(`cwd: ${process.cwd()}`);
|
|
133
|
-
p__namespace.log.info(`All files in program: ${files.map((file)=>file.fileName).join(', ')}`);
|
|
134
|
-
p__namespace.log.info(`Ignored files: ${ignores.join(', ')}`);
|
|
135
|
-
}
|
|
136
|
-
// Ignore "common files"
|
|
137
|
-
const filteredSourcePaths = files.filter((source)=>source.fileName.startsWith(Path__namespace.resolve()) && // only look ahead of current directory
|
|
138
|
-
!source.fileName.includes('/trpc/packages/') && // relative paths when running codemod locally
|
|
139
|
-
!source.fileName.includes('/node_modules/') && // always ignore node_modules
|
|
140
|
-
!ignores.includes(source.fileName)).map((source)=>source.fileName);
|
|
141
|
-
if (process.env.VERBOSE) {
|
|
142
|
-
p__namespace.log.info(`Filtered files: ${filteredSourcePaths.join(', ')}`);
|
|
143
|
-
}
|
|
144
|
-
return filteredSourcePaths;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function getPackageManager() {
|
|
148
|
-
const userAgent = process.env.npm_config_user_agent;
|
|
149
|
-
if (userAgent?.startsWith('pnpm')) return 'pnpm';
|
|
150
|
-
if (userAgent?.startsWith('yarn')) return 'yarn';
|
|
151
|
-
if (userAgent?.startsWith('bun')) return 'bun';
|
|
152
|
-
return 'npm';
|
|
153
|
-
}
|
|
154
|
-
async function installPackage(packageName) {
|
|
155
|
-
const packageManager = getPackageManager();
|
|
156
|
-
const installCmd = packageManager === 'yarn' ? 'add' : 'install';
|
|
157
|
-
const { stdout, stderr } = await execa(`${packageManager} ${installCmd} ${packageName}`);
|
|
158
|
-
if (stderr) {
|
|
159
|
-
p__namespace.log.error(stderr);
|
|
160
|
-
}
|
|
161
|
-
p__namespace.log.info(stdout);
|
|
162
|
-
}
|
|
163
|
-
async function uninstallPackage(packageName) {
|
|
164
|
-
const packageManager = getPackageManager();
|
|
165
|
-
const uninstallCmd = packageManager === 'yarn' ? 'remove' : 'uninstall';
|
|
166
|
-
const { stdout, stderr } = await execa(`${packageManager} ${uninstallCmd} ${packageName}`);
|
|
167
|
-
if (stderr) {
|
|
168
|
-
p__namespace.log.error(stderr);
|
|
169
|
-
}
|
|
170
|
-
p__namespace.log.info(stdout);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
void (async ()=>{
|
|
174
|
-
const args$1 = args.parse(process.argv.slice(2), {
|
|
175
|
-
default: {
|
|
176
|
-
force: false,
|
|
177
|
-
skipTanstackQuery: false,
|
|
178
|
-
verbose: false
|
|
179
|
-
},
|
|
180
|
-
alias: {
|
|
181
|
-
f: 'force',
|
|
182
|
-
h: 'help',
|
|
183
|
-
v: 'verbose',
|
|
184
|
-
q: 'skipTanstackQuery'
|
|
185
|
-
},
|
|
186
|
-
boolean: true
|
|
187
|
-
});
|
|
188
|
-
p.intro(`tRPC Upgrade CLI v${version}`);
|
|
189
|
-
if (args$1.help) {
|
|
190
|
-
p.log.info(`
|
|
191
|
-
Usage: upgrade [options]
|
|
192
|
-
|
|
193
|
-
Options:
|
|
194
|
-
-f, --force Skip git status check, use with caution
|
|
195
|
-
-q, --skipTanstackQuery Skip installing @trpc/tanstack-react-query package
|
|
196
|
-
-v, --verbose Enable verbose logging
|
|
197
|
-
-h, --help Show help
|
|
198
|
-
`.trim());
|
|
199
|
-
process.exit(0);
|
|
200
|
-
}
|
|
201
|
-
if (args$1.verbose) {
|
|
202
|
-
p.log.info(`Running upgrade with args: ${JSON.stringify(args$1, null, 2)}`);
|
|
203
|
-
}
|
|
204
|
-
if (!args$1.force) {
|
|
205
|
-
await assertCleanGitTree();
|
|
206
|
-
}
|
|
207
|
-
const transforms = await p.multiselect({
|
|
208
|
-
message: 'Select transforms to run',
|
|
209
|
-
options: [
|
|
210
|
-
{
|
|
211
|
-
value: require.resolve('@trpc/upgrade/transforms/hooksToOptions'),
|
|
212
|
-
label: 'Migrate Hooks to xxxOptions API'
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
value: require.resolve('@trpc/upgrade/transforms/provider'),
|
|
216
|
-
label: 'Migrate context provider setup'
|
|
217
|
-
}
|
|
218
|
-
]
|
|
219
|
-
});
|
|
220
|
-
if (p.isCancel(transforms)) process.exit(0);
|
|
221
|
-
// Make sure provider transform runs first if it's selected
|
|
222
|
-
const sortedTransforms = transforms.sort((a)=>a.includes('provider') ? -1 : 1);
|
|
223
|
-
const program = getProgram(args$1);
|
|
224
|
-
const sourceFiles = program.getSourceFiles();
|
|
225
|
-
const possibleReferences = findTRPCImportReferences(program);
|
|
226
|
-
const trpcFile = possibleReferences.mostUsed.file;
|
|
227
|
-
const trpcImportName = possibleReferences.importName;
|
|
228
|
-
const commitedFiles = await filterIgnored(sourceFiles);
|
|
229
|
-
for (const transform of sortedTransforms){
|
|
230
|
-
p.log.info(`Running transform: ${transform}`);
|
|
231
|
-
const { run } = await import('jscodeshift/src/Runner.js');
|
|
232
|
-
await run(transform, commitedFiles, {
|
|
233
|
-
...args$1,
|
|
234
|
-
trpcFile,
|
|
235
|
-
trpcImportName
|
|
236
|
-
});
|
|
237
|
-
p.log.info(`Transform ${transform} completed`);
|
|
238
|
-
}
|
|
239
|
-
if (!args$1.skipTanstackQuery) {
|
|
240
|
-
p.log.info('Installing @trpc/tanstack-react-query');
|
|
241
|
-
await installPackage('@trpc/tanstack-react-query');
|
|
242
|
-
p.log.success('@trpc/tanstack-react-query installed');
|
|
243
|
-
p.log.info('Uninstalling @trpc/react-query');
|
|
244
|
-
await uninstallPackage('@trpc/react-query');
|
|
245
|
-
p.log.success('@trpc/react-query uninstalled');
|
|
246
|
-
}
|
|
247
|
-
p.outro('Upgrade complete! 🎉');
|
|
248
|
-
})();
|